summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.in2
-rw-r--r--aclocal.m4278
-rw-r--r--config.h.in3
-rwxr-xr-xconfigure247
-rw-r--r--configure.ac36
-rw-r--r--pcap-int.h7
-rw-r--r--pcap-rpcap.c391
-rw-r--r--pcap.c30
-rw-r--r--pcap/pcap.h5
-rw-r--r--rpcap-protocol.c6
-rw-r--r--rpcap-protocol.h3
-rw-r--r--rpcapd/Makefile.in2
-rw-r--r--rpcapd/daemon.c269
-rw-r--r--rpcapd/daemon.h10
-rw-r--r--rpcapd/rpcapd.c188
-rw-r--r--sockutils.c38
-rw-r--r--sockutils.h10
-rw-r--r--sslutils.c227
-rw-r--r--sslutils.h70
19 files changed, 1543 insertions, 279 deletions
diff --git a/Makefile.in b/Makefile.in
index 9f4683e4..031a7790 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -366,6 +366,8 @@ EXTRA_DIST = \
rpcapd/win32-svc.h \
sockutils.c \
sockutils.h \
+ sslutils.c \
+ sslutils.h \
scanner.l \
testprogs/CMakeLists.txt \
testprogs/Makefile.in \
diff --git a/aclocal.m4 b/aclocal.m4
index 1dfb1af5..e4c72082 100644
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -977,3 +977,281 @@ AC_DEFUN(AC_LBL_LIBRARY_NET, [
# DLPI needs putmsg under HPUX so test for -lstr while we're at it
AC_SEARCH_LIBS(putmsg, str)
])
+
+m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
+dnl pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
+dnl serial 11 (pkg-config-0.29)
+dnl
+dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
+dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com>
+dnl
+dnl This program is free software; you can redistribute it and/or modify
+dnl it under the terms of the GNU General Public License as published by
+dnl the Free Software Foundation; either version 2 of the License, or
+dnl (at your option) any later version.
+dnl
+dnl This program is distributed in the hope that it will be useful, but
+dnl WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+dnl General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU General Public License
+dnl along with this program; if not, write to the Free Software
+dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+dnl 02111-1307, USA.
+dnl
+dnl As a special exception to the GNU General Public License, if you
+dnl distribute this file as part of a program that contains a
+dnl configuration script generated by Autoconf, you may include it under
+dnl the same distribution terms that you use for the rest of that
+dnl program.
+
+dnl PKG_PREREQ(MIN-VERSION)
+dnl -----------------------
+dnl Since: 0.29
+dnl
+dnl Verify that the version of the pkg-config macros are at least
+dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's
+dnl installed version of pkg-config, this checks the developer's version
+dnl of pkg.m4 when generating configure.
+dnl
+dnl To ensure that this macro is defined, also add:
+dnl m4_ifndef([PKG_PREREQ],
+dnl [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])])
+dnl
+dnl See the "Since" comment for each macro you use to see what version
+dnl of the macros you require.
+m4_defun([PKG_PREREQ],
+[m4_define([PKG_MACROS_VERSION], [0.29])
+m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1,
+ [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])])
+])dnl PKG_PREREQ
+
+dnl PKG_PROG_PKG_CONFIG([MIN-VERSION])
+dnl ----------------------------------
+dnl Since: 0.16
+dnl
+dnl Search for the pkg-config tool and set the PKG_CONFIG variable to
+dnl first found in the path. Checks that the version of pkg-config found
+dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is
+dnl used since that's the first version where most current features of
+dnl pkg-config existed.
+AC_DEFUN([PKG_PROG_PKG_CONFIG],
+[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
+m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$])
+m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$])
+AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])
+AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path])
+AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path])
+
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+ AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
+fi
+if test -n "$PKG_CONFIG"; then
+ _pkg_min_version=m4_default([$1], [0.9.0])
+ AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version])
+ if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ PKG_CONFIG=""
+ fi
+fi[]dnl
+])dnl PKG_PROG_PKG_CONFIG
+
+dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+dnl -------------------------------------------------------------------
+dnl Since: 0.18
+dnl
+dnl Check to see whether a particular set of modules exists. Similar to
+dnl PKG_CHECK_MODULES(), but does not set variables or print errors.
+dnl
+dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
+dnl only at the first occurence in configure.ac, so if the first place
+dnl it's called might be skipped (such as if it is within an "if", you
+dnl have to call PKG_CHECK_EXISTS manually
+AC_DEFUN([PKG_CHECK_EXISTS],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+if test -n "$PKG_CONFIG" && \
+ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then
+ m4_default([$2], [:])
+m4_ifvaln([$3], [else
+ $3])dnl
+fi])
+
+dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
+dnl ---------------------------------------------
+dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting
+dnl pkg_failed based on the result.
+m4_define([_PKG_CONFIG],
+[if test -n "$$1"; then
+ pkg_cv_[]$1="$$1"
+ elif test -n "$PKG_CONFIG"; then
+ PKG_CHECK_EXISTS([$3],
+ [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes ],
+ [pkg_failed=yes])
+ else
+ pkg_failed=untried
+fi[]dnl
+])dnl _PKG_CONFIG
+
+dnl _PKG_SHORT_ERRORS_SUPPORTED
+dnl ---------------------------
+dnl Internal check to see if pkg-config supports short errors.
+AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi[]dnl
+])dnl _PKG_SHORT_ERRORS_SUPPORTED
+
+
+dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
+dnl [ACTION-IF-NOT-FOUND])
+dnl --------------------------------------------------------------
+dnl Since: 0.4.0
+dnl
+dnl Note that if there is a possibility the first call to
+dnl PKG_CHECK_MODULES might not happen, you should be sure to include an
+dnl explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
+AC_DEFUN([PKG_CHECK_MODULES],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
+AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
+
+pkg_failed=no
+AC_MSG_CHECKING([for $1])
+
+_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
+_PKG_CONFIG([$1][_LIBS], [libs], [$2])
+
+m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS
+and $1[]_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details.])
+
+if test $pkg_failed = yes; then
+ AC_MSG_RESULT([no])
+ _PKG_SHORT_ERRORS_SUPPORTED
+ if test $_pkg_short_errors_supported = yes; then
+ $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1`
+ else
+ $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
+
+ m4_default([$4], [AC_MSG_ERROR(
+[Package requirements ($2) were not met:
+
+$$1_PKG_ERRORS
+
+Consider adjusting the PKG_CONFIG_PATH environment variable if you
+installed software in a non-standard prefix.
+
+_PKG_TEXT])[]dnl
+ ])
+elif test $pkg_failed = untried; then
+ AC_MSG_RESULT([no])
+ m4_default([$4], [AC_MSG_FAILURE(
+[The pkg-config script could not be found or is too old. Make sure it
+is in your PATH or set the PKG_CONFIG environment variable to the full
+path to pkg-config.
+
+_PKG_TEXT
+
+To get pkg-config, see <http://pkg-config.freedesktop.org/>.])[]dnl
+ ])
+else
+ $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
+ $1[]_LIBS=$pkg_cv_[]$1[]_LIBS
+ AC_MSG_RESULT([yes])
+ $3
+fi[]dnl
+])dnl PKG_CHECK_MODULES
+
+
+dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
+dnl [ACTION-IF-NOT-FOUND])
+dnl ---------------------------------------------------------------------
+dnl Since: 0.29
+dnl
+dnl Checks for existence of MODULES and gathers its build flags with
+dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags
+dnl and VARIABLE-PREFIX_LIBS from --libs.
+dnl
+dnl Note that if there is a possibility the first call to
+dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to
+dnl include an explicit call to PKG_PROG_PKG_CONFIG in your
+dnl configure.ac.
+AC_DEFUN([PKG_CHECK_MODULES_STATIC],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+_save_PKG_CONFIG=$PKG_CONFIG
+PKG_CONFIG="$PKG_CONFIG --static"
+PKG_CHECK_MODULES($@)
+PKG_CONFIG=$_save_PKG_CONFIG[]dnl
+])dnl PKG_CHECK_MODULES_STATIC
+
+
+dnl PKG_INSTALLDIR([DIRECTORY])
+dnl -------------------------
+dnl Since: 0.27
+dnl
+dnl Substitutes the variable pkgconfigdir as the location where a module
+dnl should install pkg-config .pc files. By default the directory is
+dnl $libdir/pkgconfig, but the default can be changed by passing
+dnl DIRECTORY. The user can override through the --with-pkgconfigdir
+dnl parameter.
+AC_DEFUN([PKG_INSTALLDIR],
+[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])])
+m4_pushdef([pkg_description],
+ [pkg-config installation directory @<:@]pkg_default[@:>@])
+AC_ARG_WITH([pkgconfigdir],
+ [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],,
+ [with_pkgconfigdir=]pkg_default)
+AC_SUBST([pkgconfigdir], [$with_pkgconfigdir])
+m4_popdef([pkg_default])
+m4_popdef([pkg_description])
+])dnl PKG_INSTALLDIR
+
+
+dnl PKG_NOARCH_INSTALLDIR([DIRECTORY])
+dnl --------------------------------
+dnl Since: 0.27
+dnl
+dnl Substitutes the variable noarch_pkgconfigdir as the location where a
+dnl module should install arch-independent pkg-config .pc files. By
+dnl default the directory is $datadir/pkgconfig, but the default can be
+dnl changed by passing DIRECTORY. The user can override through the
+dnl --with-noarch-pkgconfigdir parameter.
+AC_DEFUN([PKG_NOARCH_INSTALLDIR],
+[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])])
+m4_pushdef([pkg_description],
+ [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@])
+AC_ARG_WITH([noarch-pkgconfigdir],
+ [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],,
+ [with_noarch_pkgconfigdir=]pkg_default)
+AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir])
+m4_popdef([pkg_default])
+m4_popdef([pkg_description])
+])dnl PKG_NOARCH_INSTALLDIR
+
+
+dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
+dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+dnl -------------------------------------------
+dnl Since: 0.28
+dnl
+dnl Retrieves the value of the pkg-config variable for the given module.
+AC_DEFUN([PKG_CHECK_VAR],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl
+
+_PKG_CONFIG([$1], [variable="][$3]["], [$2])
+AS_VAR_COPY([$1], [pkg_cv_][$1])
+
+AS_VAR_IF([$1], [""], [$5], [$4])dnl
+])dnl PKG_CHECK_VAR
+
diff --git a/config.h.in b/config.h.in
index c554d25d..e09bc607 100644
--- a/config.h.in
+++ b/config.h.in
@@ -141,6 +141,9 @@
/* Define to 1 if you have the <net/raw.h> header file. */
#undef HAVE_NET_RAW_H
+/* Use OpenSSL */
+#undef HAVE_OPENSSL
+
/* if there's an os_proto.h for this platform, to use additional prototypes */
#undef HAVE_OS_PROTO_H
diff --git a/configure b/configure
index 7de6c148..0acb192d 100755
--- a/configure
+++ b/configure
@@ -671,6 +671,11 @@ YACC
LEXLIB
LEX_OUTPUT_ROOT
LEX
+OPENSSL_LIBS
+OPENSSL_CFLAGS
+PKG_CONFIG_LIBDIR
+PKG_CONFIG_PATH
+PKG_CONFIG
PCAP_SUPPORT_PACKET_RING
VALGRINDTEST_SRC
LIBOBJS
@@ -774,6 +779,11 @@ LDFLAGS
LIBS
CPPFLAGS
CPP
+PKG_CONFIG
+PKG_CONFIG_PATH
+PKG_CONFIG_LIBDIR
+OPENSSL_CFLAGS
+OPENSSL_LIBS
YACC
YFLAGS'
@@ -1448,6 +1458,15 @@ Some influential environment variables:
CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
you have headers in a nonstandard directory <include dir>
CPP C preprocessor
+ PKG_CONFIG path to pkg-config utility
+ PKG_CONFIG_PATH
+ directories to add to pkg-config's search path
+ PKG_CONFIG_LIBDIR
+ path overriding pkg-config's built-in search path
+ OPENSSL_CFLAGS
+ C compiler flags for OPENSSL, overriding pkg-config
+ OPENSSL_LIBS
+ linker flags for OPENSSL, overriding pkg-config
YACC The `Yet Another Compiler Compiler' implementation to use.
Defaults to the first program found out of: `bison -y', `byacc',
`yacc'.
@@ -7727,10 +7746,212 @@ _ACEOF
fi
+ #
+ # Optionally, we may want to forward packets over SSL:
+ #
+
+
+
+
+
+
+
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
+set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_PKG_CONFIG+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $PKG_CONFIG in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+fi
+PKG_CONFIG=$ac_cv_path_PKG_CONFIG
+if test -n "$PKG_CONFIG"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
+$as_echo "$PKG_CONFIG" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_path_PKG_CONFIG"; then
+ ac_pt_PKG_CONFIG=$PKG_CONFIG
+ # Extract the first word of "pkg-config", so it can be a program name with args.
+set dummy pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $ac_pt_PKG_CONFIG in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+fi
+ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG
+if test -n "$ac_pt_PKG_CONFIG"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5
+$as_echo "$ac_pt_PKG_CONFIG" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_pt_PKG_CONFIG" = x; then
+ PKG_CONFIG=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ PKG_CONFIG=$ac_pt_PKG_CONFIG
+ fi
+else
+ PKG_CONFIG="$ac_cv_path_PKG_CONFIG"
+fi
+
+fi
+if test -n "$PKG_CONFIG"; then
+ _pkg_min_version=0.9.0
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5
+$as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; }
+ if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ PKG_CONFIG=""
+ fi
+fi
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for OPENSSL" >&5
+$as_echo_n "checking for OPENSSL... " >&6; }
+
+if test -n "$OPENSSL_CFLAGS"; then
+ pkg_cv_OPENSSL_CFLAGS="$OPENSSL_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"openssl\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "openssl") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_OPENSSL_CFLAGS=`$PKG_CONFIG --cflags "openssl" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+if test -n "$OPENSSL_LIBS"; then
+ pkg_cv_OPENSSL_LIBS="$OPENSSL_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"openssl\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "openssl") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_OPENSSL_LIBS=`$PKG_CONFIG --libs "openssl" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi
+ if test $_pkg_short_errors_supported = yes; then
+ OPENSSL_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "openssl" 2>&1`
+ else
+ OPENSSL_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "openssl" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$OPENSSL_PKG_ERRORS" >&5
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: No openssl detected" >&5
+$as_echo "$as_me: No openssl detected" >&6;}
+elif test $pkg_failed = untried; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: No openssl detected" >&5
+$as_echo "$as_me: No openssl detected" >&6;}
+else
+ OPENSSL_CFLAGS=$pkg_cv_OPENSSL_CFLAGS
+ OPENSSL_LIBS=$pkg_cv_OPENSSL_LIBS
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+$as_echo "#define HAVE_OPENSSL 1" >>confdefs.h
+
+ CFLAGS="$CFLAGS $OPENSSL_CFLAGS"
+ LIBS="$LIBS $OPENSSL_LIBS"
+ HAVE_OPENSSL="yes"
+fi
+
$as_echo "#define ENABLE_REMOTE /**/" >>confdefs.h
- MSRC="$MSRC pcap-new.c pcap-rpcap.c rpcap-protocol.c sockutils.c"
+ MSRC="$MSRC pcap-new.c pcap-rpcap.c rpcap-protocol.c sockutils.c sslutils.c"
BUILD_RPCAPD=build-rpcapd
INSTALL_RPCAPD=install-rpcapd
;;
@@ -8225,8 +8446,20 @@ if ac_fn_c_try_compile "$LINENO"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
- V_LIB_CCOPT_FAT="-arch x86_64 -arch i386"
- V_LIB_LDFLAGS_FAT="-arch x86_64 -arch i386"
+ V_LIB_CCOPT_FAT="-arch x86_64"
+ V_LIB_LDFLAGS_FAT="-arch x86_64"
+
+ #
+ # OpenSSL installation on macOS seems
+ # to install only the libs for 64-bit
+ # x86 - at least that's what Brew does:
+ # only configure 32-bit builds if we
+ # don't have OpenSSL.
+ #
+ if test "$HAVE_OPENSSL" != yes; then
+ V_LIB_CCOPT_FAT="$V_LIB_CCOPT_FAT -arch i386"
+ V_LIB_LDFLAGS_FAT="$V_LIB_LDFLAGS_FAT -arch i386"
+ fi
else
@@ -8260,6 +8493,14 @@ $as_echo "$as_me: WARNING: Compiling for 32-bit x86 gives an error; try installi
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
CFLAGS="$save_CFLAGS"
+ if test "$HAVE_OPENSSL" = yes; then
+ #
+ # If all else fails, look for OpenSSL in
+ # /usr/local/opt.
+ #
+ CFLAGS="$CFLAGS -I/usr/local/opt/openssl/include"
+ LIBS="$LIBS -L/usr/local/opt/openssl/lib"
+ fi
;;
esac
fi
diff --git a/configure.ac b/configure.ac
index 55a79474..069d9f8a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1487,9 +1487,19 @@ yes) AC_MSG_RESULT(yes)
#include <sys/socket.h>
])
+ #
+ # Optionally, we may want to forward packets over SSL:
+ #
+ PKG_CHECK_MODULES([OPENSSL], [openssl],
+ [AC_DEFINE([HAVE_OPENSSL], [1], [Use OpenSSL])
+ CFLAGS="$CFLAGS $OPENSSL_CFLAGS"
+ LIBS="$LIBS $OPENSSL_LIBS"
+ HAVE_OPENSSL="yes"],
+ AC_MSG_NOTICE(No openssl detected))
+
AC_DEFINE(ENABLE_REMOTE,,
[Define to 1 if remote packet capture is to be supported])
- MSRC="$MSRC pcap-new.c pcap-rpcap.c rpcap-protocol.c sockutils.c"
+ MSRC="$MSRC pcap-new.c pcap-rpcap.c rpcap-protocol.c sockutils.c sslutils.c"
BUILD_RPCAPD=build-rpcapd
INSTALL_RPCAPD=install-rpcapd
;;
@@ -1738,8 +1748,20 @@ darwin*)
[return 0;],
[
AC_MSG_RESULT(yes)
- V_LIB_CCOPT_FAT="-arch x86_64 -arch i386"
- V_LIB_LDFLAGS_FAT="-arch x86_64 -arch i386"
+ V_LIB_CCOPT_FAT="-arch x86_64"
+ V_LIB_LDFLAGS_FAT="-arch x86_64"
+
+ #
+ # OpenSSL installation on macOS seems
+ # to install only the libs for 64-bit
+ # x86 - at least that's what Brew does:
+ # only configure 32-bit builds if we
+ # don't have OpenSSL.
+ #
+ if test "$HAVE_OPENSSL" != yes; then
+ V_LIB_CCOPT_FAT="$V_LIB_CCOPT_FAT -arch i386"
+ V_LIB_LDFLAGS_FAT="$V_LIB_LDFLAGS_FAT -arch i386"
+ fi
],
[
AC_MSG_RESULT(no)
@@ -1767,6 +1789,14 @@ darwin*)
esac
])
CFLAGS="$save_CFLAGS"
+ if test "$HAVE_OPENSSL" = yes; then
+ #
+ # If all else fails, look for OpenSSL in
+ # /usr/local/opt.
+ #
+ CFLAGS="$CFLAGS -I/usr/local/opt/openssl/include"
+ LIBS="$LIBS -L/usr/local/opt/openssl/lib"
+ fi
;;
esac
fi
diff --git a/pcap-int.h b/pcap-int.h
index 4bab336f..ec643eba 100644
--- a/pcap-int.h
+++ b/pcap-int.h
@@ -529,6 +529,13 @@ int install_bpf_program(pcap_t *, struct bpf_program *);
int pcap_strcasecmp(const char *, const char *);
+/*
+ * Internal interface for pcap_parsesrcstr with the additional bit of
+ * information regarding SSL support (rpcap:// vs rpcaps://)
+ */
+int pcap_parsesrcstr_ex(const char *source, int *type, char *host, char *port,
+ char *name, unsigned char *uses_ssl, char *errbuf);
+
#ifdef YYDEBUG
extern int pcap_debug;
#endif
diff --git a/pcap-rpcap.c b/pcap-rpcap.c
index 16dcbf8f..6e45c433 100644
--- a/pcap-rpcap.c
+++ b/pcap-rpcap.c
@@ -46,6 +46,10 @@
#include "rpcap-protocol.h"
#include "pcap-rpcap.h"
+#ifdef HAVE_OPENSSL
+#include "sslutils.h"
+#endif
+
/*
* This file contains the pcap module for capturing from a remote machine's
* interfaces using the RPCAP protocol.
@@ -83,6 +87,7 @@ struct activehosts
{
struct sockaddr_storage host;
SOCKET sockctrl;
+ SSL *ssl;
uint8 protocol_version;
struct activehosts *next;
};
@@ -97,6 +102,7 @@ static struct activehosts *activeHosts;
* pcap_remoteact_cleanup() for more details.
*/
static SOCKET sockmain;
+static SSL *ssl_main;
/*
* Private data for capturing remotely using the rpcap protocol.
@@ -111,11 +117,13 @@ struct pcap_rpcap {
SOCKET rmt_sockctrl; /* socket ID of the socket used for the control connection */
SOCKET rmt_sockdata; /* socket ID of the socket used for the data connection */
+ SSL *ctrl_ssl, *data_ssl; /* optional transport of rmt_sockctrl and rmt_sockdata via TLS */
int rmt_flags; /* we have to save flags, since they are passed by the pcap_open_live(), but they are used by the pcap_startcapture() */
int rmt_capstarted; /* 'true' if the capture is already started (needed to knoe if we have to call the pcap_startcapture() */
char *currentfilter; /* Pointer to a buffer (allocated at run-time) that stores the current filter. Needed when flag PCAP_OPENFLAG_NOCAPTURE_RPCAP is turned on. */
uint8 protocol_version; /* negotiated protocol version */
+ uint8 uses_ssl; /* User asked for rpcaps scheme */
unsigned int TotNetDrops; /* keeps the number of packets that have been dropped by the network */
@@ -155,15 +163,15 @@ static void pcap_save_current_filter_rpcap(pcap_t *fp, const char *filter);
static int pcap_setfilter_rpcap(pcap_t *fp, struct bpf_program *prog);
static int pcap_setsampling_remote(pcap_t *fp);
static int pcap_startcapture_remote(pcap_t *fp);
-static int rpcap_sendauth(SOCKET sock, uint8 *ver, struct pcap_rmtauth *auth, char *errbuf);
-static int rpcap_recv_msg_header(SOCKET sock, struct rpcap_header *header, char *errbuf);
-static int rpcap_check_msg_ver(SOCKET sock, uint8 expected_ver, struct rpcap_header *header, char *errbuf);
-static int rpcap_check_msg_type(SOCKET sock, uint8 request_type, struct rpcap_header *header, uint16 *errcode, char *errbuf);
-static int rpcap_process_msg_header(SOCKET sock, uint8 ver, uint8 request_type, struct rpcap_header *header, char *errbuf);
-static int rpcap_recv(SOCKET sock, void *buffer, size_t toread, uint32 *plen, char *errbuf);
-static void rpcap_msg_err(SOCKET sockctrl, uint32 plen, char *remote_errbuf);
-static int rpcap_discard(SOCKET sock, uint32 len, char *errbuf);
-static int rpcap_read_packet_msg(SOCKET sock, pcap_t *p, size_t size);
+static int rpcap_sendauth(SOCKET sock, SSL *, uint8 *ver, struct pcap_rmtauth *auth, char *errbuf);
+static int rpcap_recv_msg_header(SOCKET sock, SSL *, struct rpcap_header *header, char *errbuf);
+static int rpcap_check_msg_ver(SOCKET sock, SSL *, uint8 expected_ver, struct rpcap_header *header, char *errbuf);
+static int rpcap_check_msg_type(SOCKET sock, SSL *, uint8 request_type, struct rpcap_header *header, uint16 *errcode, char *errbuf);
+static int rpcap_process_msg_header(SOCKET sock, SSL *, uint8 ver, uint8 request_type, struct rpcap_header *header, char *errbuf);
+static int rpcap_recv(SOCKET sock, SSL *, void *buffer, size_t toread, uint32 *plen, char *errbuf);
+static void rpcap_msg_err(SOCKET sockctrl, SSL *, uint32 plen, char *remote_errbuf);
+static int rpcap_discard(SOCKET sock, SSL *, uint32 len, char *errbuf);
+static int rpcap_read_packet_msg(struct pcap_rpcap const *, pcap_t *p, size_t size);
/****************************************************
* *
@@ -376,7 +384,7 @@ static int pcap_read_nocb_remote(pcap_t *p, struct pcap_pkthdr *pkt_header, u_ch
struct rpcap_pkthdr *net_pkt_header; /* header of the packet, from the message */
u_char *net_pkt_data; /* packet data from the message */
uint32 plen;
- int retval; /* generic return value */
+ int retval = 0; /* generic return value */
int msglen;
/* Structures needed for the select() call */
@@ -390,27 +398,36 @@ static int pcap_read_nocb_remote(pcap_t *p, struct pcap_pkthdr *pkt_header, u_ch
tv.tv_sec = p->opt.timeout / 1000;
tv.tv_usec = (suseconds_t)((p->opt.timeout - tv.tv_sec * 1000) * 1000);
- /* Watch out sockdata to see if it has input */
- FD_ZERO(&rfds);
+#ifdef HAVE_OPENSSL
+ /* Check if we still have bytes available in the last decoded TLS record.
+ * If that's the case, we know SSL_read will not block. */
+ retval = pr->data_ssl && SSL_pending(pr->data_ssl) > 0;
+#endif
+ if (! retval)
+ {
+ /* Watch out sockdata to see if it has input */
+ FD_ZERO(&rfds);
- /*
- * 'fp->rmt_sockdata' has always to be set before calling the select(),
- * since it is cleared by the select()
- */
- FD_SET(pr->rmt_sockdata, &rfds);
+ /*
+ * 'fp->rmt_sockdata' has always to be set before calling the select(),
+ * since it is cleared by the select()
+ */
+ FD_SET(pr->rmt_sockdata, &rfds);
- retval = select((int) pr->rmt_sockdata + 1, &rfds, NULL, NULL, &tv);
- if (retval == -1)
- {
-#ifndef _WIN32
- if (errno == EINTR)
+ retval = select((int) pr->rmt_sockdata + 1, &rfds, NULL, NULL, &tv);
+
+ if (retval == -1)
{
- /* Interrupted. */
- return 0;
- }
+#ifndef _WIN32
+ if (errno == EINTR)
+ {
+ /* Interrupted. */
+ return 0;
+ }
#endif
- sock_geterror("select(): ", p->errbuf, PCAP_ERRBUF_SIZE);
- return -1;
+ sock_geterror("select(): ", p->errbuf, PCAP_ERRBUF_SIZE);
+ return -1;
+ }
}
/* There is no data waiting, so return '0' */
@@ -428,7 +445,7 @@ static int pcap_read_nocb_remote(pcap_t *p, struct pcap_pkthdr *pkt_header, u_ch
if (pr->rmt_flags & PCAP_OPENFLAG_DATATX_UDP)
{
/* Read the entire message from the network */
- msglen = sock_recv_dgram(pr->rmt_sockdata, p->buffer,
+ msglen = sock_recv_dgram(pr->rmt_sockdata, pr->data_ssl, p->buffer,
p->bufsize, p->errbuf, PCAP_ERRBUF_SIZE);
if (msglen == -1)
{
@@ -472,8 +489,7 @@ static int pcap_read_nocb_remote(pcap_t *p, struct pcap_pkthdr *pkt_header, u_ch
* The size we should get is the size of the
* packet header.
*/
- status = rpcap_read_packet_msg(pr->rmt_sockdata, p,
- sizeof(struct rpcap_header));
+ status = rpcap_read_packet_msg(pr, p, sizeof(struct rpcap_header));
if (status == -1)
{
/* Network error. */
@@ -505,8 +521,7 @@ static int pcap_read_nocb_remote(pcap_t *p, struct pcap_pkthdr *pkt_header, u_ch
"Server sent us a message larger than the largest expected packet message");
return -1;
}
- status = rpcap_read_packet_msg(pr->rmt_sockdata, p,
- sizeof(struct rpcap_header) + plen);
+ status = rpcap_read_packet_msg(pr, p, sizeof(struct rpcap_header) + plen);
if (status == -1)
{
/* Network error. */
@@ -535,7 +550,7 @@ static int pcap_read_nocb_remote(pcap_t *p, struct pcap_pkthdr *pkt_header, u_ch
/*
* Did the server specify the version we negotiated?
*/
- if (rpcap_check_msg_ver(pr->rmt_sockdata, pr->protocol_version,
+ if (rpcap_check_msg_ver(pr->rmt_sockdata, pr->data_ssl, pr->protocol_version,
header, p->errbuf) == -1)
{
return 0; /* Return 'no packets received' */
@@ -715,7 +730,7 @@ static void pcap_cleanup_rpcap(pcap_t *fp)
* we're closing this pcap_t, and have no place to report
* the error. No reply is sent to this message.
*/
- (void)sock_send(pr->rmt_sockctrl, (char *)&header,
+ (void)sock_send(pr->rmt_sockctrl, pr->ctrl_ssl, (char *)&header,
sizeof(struct rpcap_header), NULL, 0);
}
else
@@ -728,7 +743,7 @@ static void pcap_cleanup_rpcap(pcap_t *fp)
* as we're closing this pcap_t, and have no place to
* report the error.
*/
- if (sock_send(pr->rmt_sockctrl, (char *)&header,
+ if (sock_send(pr->rmt_sockctrl, pr->ctrl_ssl, (char *)&header,
sizeof(struct rpcap_header), NULL, 0) == 0)
{
/*
@@ -736,11 +751,11 @@ static void pcap_cleanup_rpcap(pcap_t *fp)
* as we're closing this pcap_t, and have no
* place to report the error.
*/
- if (rpcap_process_msg_header(pr->rmt_sockctrl,
+ if (rpcap_process_msg_header(pr->rmt_sockctrl, pr->ctrl_ssl,
pr->protocol_version, RPCAP_MSG_ENDCAP_REQ,
&header, NULL) == 0)
{
- (void)rpcap_discard(pr->rmt_sockctrl,
+ (void)rpcap_discard(pr->rmt_sockctrl, pr->ctrl_ssl,
header.plen, NULL);
}
}
@@ -748,14 +763,31 @@ static void pcap_cleanup_rpcap(pcap_t *fp)
if (pr->rmt_sockdata)
{
+#ifdef HAVE_OPENSSL
+ if (pr->data_ssl)
+ {
+ SSL_free(pr->data_ssl); // Has to be done before the socket is closed
+ pr->data_ssl = NULL;
+ }
+#endif
sock_close(pr->rmt_sockdata, NULL, 0);
pr->rmt_sockdata = 0;
}
if ((!active) && (pr->rmt_sockctrl))
+ {
+#ifdef HAVE_OPENSSL
+ if (pr->ctrl_ssl)
+ {
+ SSL_free(pr->ctrl_ssl);
+ pr->ctrl_ssl = NULL;
+ }
+#endif
sock_close(pr->rmt_sockctrl, NULL, 0);
+ }
pr->rmt_sockctrl = 0;
+ pr->ctrl_ssl = NULL;
if (pr->currentfilter)
{
@@ -880,19 +912,19 @@ static struct pcap_stat *rpcap_stats_rpcap(pcap_t *p, struct pcap_stat *ps, int
RPCAP_MSG_STATS_REQ, 0, 0);
/* Send the PCAP_STATS command */
- if (sock_send(pr->rmt_sockctrl, (char *)&header,
+ if (sock_send(pr->rmt_sockctrl, pr->ctrl_ssl, (char *)&header,
sizeof(struct rpcap_header), p->errbuf, PCAP_ERRBUF_SIZE) < 0)
return NULL; /* Unrecoverable network error */
/* Receive and process the reply message header. */
- if (rpcap_process_msg_header(pr->rmt_sockctrl, pr->protocol_version,
+ if (rpcap_process_msg_header(pr->rmt_sockctrl, pr->ctrl_ssl, pr->protocol_version,
RPCAP_MSG_STATS_REQ, &header, p->errbuf) == -1)
return NULL; /* Error */
plen = header.plen;
/* Read the reply body */
- if (rpcap_recv(pr->rmt_sockctrl, (char *)&netstats,
+ if (rpcap_recv(pr->rmt_sockctrl, pr->ctrl_ssl, (char *)&netstats,
sizeof(struct rpcap_stats), &plen, p->errbuf) == -1)
goto error;
@@ -909,7 +941,7 @@ static struct pcap_stat *rpcap_stats_rpcap(pcap_t *p, struct pcap_stat *ps, int
#endif /* _WIN32 */
/* Discard the rest of the message. */
- if (rpcap_discard(pr->rmt_sockctrl, plen, p->errbuf) == -1)
+ if (rpcap_discard(pr->rmt_sockctrl, pr->ctrl_ssl, plen, p->errbuf) == -1)
goto error_nodiscard;
return ps;
@@ -920,7 +952,7 @@ error:
* We already reported an error; if this gets an error, just
* drive on.
*/
- (void)rpcap_discard(pr->rmt_sockctrl, plen, NULL);
+ (void)rpcap_discard(pr->rmt_sockctrl, pr->ctrl_ssl, plen, NULL);
error_nodiscard:
return NULL;
@@ -1040,6 +1072,10 @@ static int pcap_startcapture_remote(pcap_t *fp)
int sockbufsize = 0;
uint32 server_sockbufsize;
+ // Take the opportunity to clear pr->data_ssl before any goto error,
+ // as it seems pr->priv is not zeroed after its malloced.
+ pr->data_ssl = NULL;
+
/*
* Let's check if sampling has been required.
* If so, let's set it first
@@ -1179,18 +1215,18 @@ static int pcap_startcapture_remote(pcap_t *fp)
if (pcap_pack_bpffilter(fp, &sendbuf[sendbufidx], &sendbufidx, &fp->fcode))
goto error_nodiscard;
- if (sock_send(pr->rmt_sockctrl, sendbuf, sendbufidx, fp->errbuf,
+ if (sock_send(pr->rmt_sockctrl, pr->ctrl_ssl, sendbuf, sendbufidx, fp->errbuf,
PCAP_ERRBUF_SIZE) < 0)
goto error_nodiscard;
/* Receive and process the reply message header. */
- if (rpcap_process_msg_header(pr->rmt_sockctrl, pr->protocol_version,
+ if (rpcap_process_msg_header(pr->rmt_sockctrl, pr->ctrl_ssl, pr->protocol_version,
RPCAP_MSG_STARTCAP_REQ, &header, fp->errbuf) == -1)
goto error_nodiscard;
plen = header.plen;
- if (rpcap_recv(pr->rmt_sockctrl, (char *)&startcapreply,
+ if (rpcap_recv(pr->rmt_sockctrl, pr->ctrl_ssl, (char *)&startcapreply,
sizeof(struct rpcap_startcapreply), &plen, fp->errbuf) == -1)
goto error;
@@ -1249,6 +1285,14 @@ static int pcap_startcapture_remote(pcap_t *fp)
/* Let's save the socket of the data connection */
pr->rmt_sockdata = sockdata;
+#ifdef HAVE_OPENSSL
+ if (pr->uses_ssl)
+ {
+ pr->data_ssl = ssl_promotion(0, sockdata, fp->errbuf, PCAP_ERRBUF_SIZE);
+ if (! pr->data_ssl) goto error;
+ }
+#endif
+
/*
* Set the size of the socket buffer for the data socket.
* It has the same size as the local capture buffer used
@@ -1336,7 +1380,7 @@ static int pcap_startcapture_remote(pcap_t *fp)
fp->cc = 0;
/* Discard the rest of the message. */
- if (rpcap_discard(pr->rmt_sockctrl, plen, fp->errbuf) == -1)
+ if (rpcap_discard(pr->rmt_sockctrl, pr->ctrl_ssl, plen, fp->errbuf) == -1)
goto error_nodiscard;
/*
@@ -1376,14 +1420,31 @@ error:
* We already reported an error; if this gets an error, just
* drive on.
*/
- (void)rpcap_discard(pr->rmt_sockctrl, plen, NULL);
+ (void)rpcap_discard(pr->rmt_sockctrl, pr->ctrl_ssl, plen, NULL);
error_nodiscard:
+#ifdef HAVE_OPENSSL
+ if (pr->data_ssl)
+ {
+ SSL_free(pr->data_ssl); // Have to be done before the socket is closed
+ pr->data_ssl = NULL;
+ }
+#endif
+
if ((sockdata) && (sockdata != -1)) /* we can be here because sockdata said 'error' */
sock_close(sockdata, NULL, 0);
if (!active)
+ {
+#ifdef HAVE_OPENSSL
+ if (pr->ctrl_ssl)
+ {
+ SSL_free(pr->ctrl_ssl);
+ pr->ctrl_ssl = NULL;
+ }
+#endif
sock_close(pr->rmt_sockctrl, NULL, 0);
+ }
if (addrinfo != NULL)
freeaddrinfo(addrinfo);
@@ -1516,19 +1577,19 @@ static int pcap_updatefilter_remote(pcap_t *fp, struct bpf_program *prog)
if (pcap_pack_bpffilter(fp, &sendbuf[sendbufidx], &sendbufidx, prog))
return -1;
- if (sock_send(pr->rmt_sockctrl, sendbuf, sendbufidx, fp->errbuf,
+ if (sock_send(pr->rmt_sockctrl, pr->ctrl_ssl, sendbuf, sendbufidx, fp->errbuf,
PCAP_ERRBUF_SIZE) < 0)
return -1;
/* Receive and process the reply message header. */
- if (rpcap_process_msg_header(pr->rmt_sockctrl, pr->protocol_version,
+ if (rpcap_process_msg_header(pr->rmt_sockctrl, pr->ctrl_ssl, pr->protocol_version,
RPCAP_MSG_UPDATEFILTER_REQ, &header, fp->errbuf) == -1)
return -1;
/*
* It shouldn't have any contents; discard it if it does.
*/
- if (rpcap_discard(pr->rmt_sockctrl, header.plen, fp->errbuf) == -1)
+ if (rpcap_discard(pr->rmt_sockctrl, pr->ctrl_ssl, header.plen, fp->errbuf) == -1)
return -1;
return 0;
@@ -1761,19 +1822,19 @@ static int pcap_setsampling_remote(pcap_t *fp)
sampling_pars->method = (uint8)fp->rmt_samp.method;
sampling_pars->value = (uint16)htonl(fp->rmt_samp.value);
- if (sock_send(pr->rmt_sockctrl, sendbuf, sendbufidx, fp->errbuf,
+ if (sock_send(pr->rmt_sockctrl, pr->ctrl_ssl, sendbuf, sendbufidx, fp->errbuf,
PCAP_ERRBUF_SIZE) < 0)
return -1;
/* Receive and process the reply message header. */
- if (rpcap_process_msg_header(pr->rmt_sockctrl, pr->protocol_version,
+ if (rpcap_process_msg_header(pr->rmt_sockctrl, pr->ctrl_ssl, pr->protocol_version,
RPCAP_MSG_SETSAMPLING_REQ, &header, fp->errbuf) == -1)
return -1;
/*
* It shouldn't have any contents; discard it if it does.
*/
- if (rpcap_discard(pr->rmt_sockctrl, header.plen, fp->errbuf) == -1)
+ if (rpcap_discard(pr->rmt_sockctrl, pr->ctrl_ssl, header.plen, fp->errbuf) == -1)
return -1;
return 0;
@@ -1808,7 +1869,7 @@ static int pcap_setsampling_remote(pcap_t *fp)
* \return '0' if everything is fine, '-1' for an error. For errors,
* an error message string is returned in the 'errbuf' variable.
*/
-static int rpcap_doauth(SOCKET sockctrl, uint8 *ver, struct pcap_rmtauth *auth, char *errbuf)
+static int rpcap_doauth(SOCKET sockctrl, SSL *ssl, uint8 *ver, struct pcap_rmtauth *auth, char *errbuf)
{
int status;
@@ -1818,7 +1879,7 @@ static int rpcap_doauth(SOCKET sockctrl, uint8 *ver, struct pcap_rmtauth *auth,
* First try with the maximum version number we support.
*/
*ver = RPCAP_MAX_VERSION;
- status = rpcap_sendauth(sockctrl, ver, auth, errbuf);
+ status = rpcap_sendauth(sockctrl, ssl, ver, auth, errbuf);
if (status == 0)
{
//
@@ -1839,7 +1900,7 @@ static int rpcap_doauth(SOCKET sockctrl, uint8 *ver, struct pcap_rmtauth *auth,
* support that version. *ver has been set to that version; try
* authenticating again with that version.
*/
- status = rpcap_sendauth(sockctrl, ver, auth, errbuf);
+ status = rpcap_sendauth(sockctrl, ssl, ver, auth, errbuf);
if (status == 0)
{
//
@@ -1889,7 +1950,7 @@ static int rpcap_doauth(SOCKET sockctrl, uint8 *ver, struct pcap_rmtauth *auth,
* support, or '-1' for other errors. For errors, an error message string
* is returned in the 'errbuf' variable.
*/
-static int rpcap_sendauth(SOCKET sock, uint8 *ver, struct pcap_rmtauth *auth, char *errbuf)
+static int rpcap_sendauth(SOCKET sock, SSL *ssl, uint8 *ver, struct pcap_rmtauth *auth, char *errbuf)
{
char sendbuf[RPCAP_NETBUF_SIZE]; /* temporary buffer in which data that has to be sent is buffered */
int sendbufidx = 0; /* index which keeps the number of bytes currently buffered */
@@ -1987,14 +2048,14 @@ static int rpcap_sendauth(SOCKET sock, uint8 *ver, struct pcap_rmtauth *auth, ch
rpauth->slen2 = htons(rpauth->slen2);
}
- if (sock_send(sock, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) < 0)
+ if (sock_send(sock, ssl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) < 0)
return -1;
/* Receive the reply */
- if (rpcap_recv_msg_header(sock, &header, errbuf) == -1)
+ if (rpcap_recv_msg_header(sock, ssl, &header, errbuf) == -1)
return -1;
- if (rpcap_check_msg_type(sock, RPCAP_MSG_AUTH_REQ, &header,
+ if (rpcap_check_msg_type(sock, ssl, RPCAP_MSG_AUTH_REQ, &header,
&errcode, errbuf) == -1)
{
/* Error message - or something else, which is a protocol error. */
@@ -2039,7 +2100,7 @@ static int rpcap_sendauth(SOCKET sock, uint8 *ver, struct pcap_rmtauth *auth, ch
*
* Discard the rest of it.
*/
- if (rpcap_discard(sock, header.plen, errbuf) == -1)
+ if (rpcap_discard(sock, ssl, header.plen, errbuf) == -1)
return -1;
return 0;
@@ -2110,6 +2171,7 @@ pcap_t *pcap_open_rpcap(const char *source, int snaplen, int flags, int read_tim
struct activehosts *activeconn; /* active connection, if there is one */
int error; /* '1' if rpcap_remoteact_getsock returned an error */
SOCKET sockctrl;
+ SSL *ssl = NULL;
uint8 protocol_version; /* negotiated protocol version */
int active;
uint32 plen;
@@ -2153,12 +2215,22 @@ pcap_t *pcap_open_rpcap(const char *source, int snaplen, int flags, int read_tim
pr = fp->priv;
pr->rmt_flags = flags;
+ // Also, SSL is not supported with UDP at the moment, so if the user
+ // asks for both we'd better bail out now:
+ if (pr->uses_ssl && (pr->rmt_flags & PCAP_OPENFLAG_DATATX_UDP))
+ {
+ pcap_close(fp);
+ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "SSL not supported with UDP forward of remote packets");
+ return NULL;
+ }
+
/*
* determine the type of the source (NULL, file, local, remote)
* You must have a valid source string even if we're in active mode, because otherwise
* the call to the following function will fail.
*/
- if (pcap_parsesrcstr(fp->opt.device, &retval, host, ctrlport, iface, errbuf) == -1)
+ if (pcap_parsesrcstr_ex(fp->opt.device, &retval, host, ctrlport, iface, &pr->uses_ssl, errbuf) == -1)
{
pcap_close(fp);
return NULL;
@@ -2185,12 +2257,14 @@ pcap_t *pcap_open_rpcap(const char *source, int snaplen, int flags, int read_tim
activeconn = rpcap_remoteact_getsock(host, &error, errbuf);
if (activeconn != NULL)
{
+ active = 1;
sockctrl = activeconn->sockctrl;
+ ssl = activeconn->ssl;
protocol_version = activeconn->protocol_version;
- active = 1;
}
else
{
+ active = 0; // Must be set before jumping to error
struct addrinfo hints; /* temp, needed to open a socket connection */
struct addrinfo *addrinfo; /* temp, needed to open a socket connection */
@@ -2239,15 +2313,29 @@ pcap_t *pcap_open_rpcap(const char *source, int snaplen, int flags, int read_tim
/* addrinfo is no longer used */
freeaddrinfo(addrinfo);
- if (rpcap_doauth(sockctrl, &protocol_version, auth, errbuf) == -1)
+ if (pr->uses_ssl)
{
- sock_close(sockctrl, NULL, 0);
+#ifdef HAVE_OPENSSL
+ ssl = ssl_promotion(0, sockctrl, errbuf, PCAP_ERRBUF_SIZE);
+ if (! ssl)
+ {
+ pcap_close(fp);
+ return NULL;
+ }
+#else
+ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "No TLS support");
pcap_close(fp);
return NULL;
+#endif
}
- active = 0;
+
+ if (rpcap_doauth(sockctrl, ssl, &protocol_version, auth, errbuf) == -1)
+ goto error_nodiscard;
}
+ /* All good so far, save the ssl handler */
+ ssl_main = ssl;
+
/*
* Now it's time to start playing with the RPCAP protocol
* RPCAP open command: create the request message
@@ -2263,28 +2351,29 @@ pcap_t *pcap_open_rpcap(const char *source, int snaplen, int flags, int read_tim
RPCAP_NETBUF_SIZE, SOCKBUF_BUFFERIZE, errbuf, PCAP_ERRBUF_SIZE))
goto error_nodiscard;
- if (sock_send(sockctrl, sendbuf, sendbufidx, errbuf,
+ if (sock_send(sockctrl, ssl, sendbuf, sendbufidx, errbuf,
PCAP_ERRBUF_SIZE) < 0)
goto error_nodiscard;
/* Receive and process the reply message header. */
- if (rpcap_process_msg_header(sockctrl, protocol_version,
+ if (rpcap_process_msg_header(sockctrl, ssl, protocol_version,
RPCAP_MSG_OPEN_REQ, &header, errbuf) == -1)
goto error_nodiscard;
plen = header.plen;
/* Read the reply body */
- if (rpcap_recv(sockctrl, (char *)&openreply,
+ if (rpcap_recv(sockctrl, ssl, (char *)&openreply,
sizeof(struct rpcap_openreply), &plen, errbuf) == -1)
goto error;
/* Discard the rest of the message, if there is any. */
- if (rpcap_discard(sockctrl, plen, errbuf) == -1)
+ if (rpcap_discard(sockctrl, ssl, plen, errbuf) == -1)
goto error_nodiscard;
/* Set proper fields into the pcap_t struct */
fp->linktype = ntohl(openreply.linktype);
pr->rmt_sockctrl = sockctrl;
+ pr->ctrl_ssl = ssl;
pr->protocol_version = protocol_version;
pr->rmt_clientside = 1;
@@ -2316,11 +2405,16 @@ error:
* We already reported an error; if this gets an error, just
* drive on.
*/
- (void)rpcap_discard(sockctrl, plen, NULL);
+ (void)rpcap_discard(sockctrl, pr->ctrl_ssl, plen, NULL);
error_nodiscard:
if (!active)
+ {
+#ifdef HAVE_OPENSSL
+ if (ssl) SSL_free(ssl); // Have to be done before the socket is closed
+#endif
sock_close(sockctrl, NULL, 0);
+ }
pcap_close(fp);
return NULL;
@@ -2348,6 +2442,7 @@ pcap_findalldevs_ex_remote(const char *source, struct pcap_rmtauth *auth, pcap_i
int error; /* '1' if rpcap_remoteact_getsock returned an error */
uint8 protocol_version; /* protocol version */
SOCKET sockctrl; /* socket descriptor of the control connection */
+ SSL *ssl = NULL; /* optional SSL handler for sockctrl */
uint32 plen;
struct rpcap_header header; /* structure that keeps the general header of the rpcap protocol */
int i, j; /* temp variables */
@@ -2355,6 +2450,7 @@ pcap_findalldevs_ex_remote(const char *source, struct pcap_rmtauth *auth, pcap_i
int active; /* 'true' if we the other end-party is in active mode */
int type;
char host[PCAP_BUF_SIZE], port[PCAP_BUF_SIZE];
+ uint8 uses_ssl;
char tmpstring[PCAP_BUF_SIZE + 1]; /* Needed to convert names and descriptions from 'old' syntax to the 'new' one */
pcap_if_t *lastdev; /* Last device in the pcap_if_t list */
pcap_if_t *dev; /* Device we're adding to the pcap_if_t list */
@@ -2364,7 +2460,7 @@ pcap_findalldevs_ex_remote(const char *source, struct pcap_rmtauth *auth, pcap_i
lastdev = NULL;
/* Retrieve the needed data for getting adapter list */
- if (pcap_parsesrcstr(source, &type, host, port, NULL, errbuf) == -1)
+ if (pcap_parsesrcstr_ex(source, &type, host, port, NULL, &uses_ssl, errbuf) == -1)
return -1;
/* Warning: this call can be the first one called by the user. */
@@ -2376,12 +2472,14 @@ pcap_findalldevs_ex_remote(const char *source, struct pcap_rmtauth *auth, pcap_i
activeconn = rpcap_remoteact_getsock(host, &error, errbuf);
if (activeconn != NULL)
{
+ active = 1;
sockctrl = activeconn->sockctrl;
+ ssl = activeconn->ssl;
protocol_version = activeconn->protocol_version;
- active = 1;
}
else
{
+ active = 0;
struct addrinfo hints; /* temp variable needed to resolve hostnames into to socket representation */
struct addrinfo *addrinfo; /* temp variable needed to resolve hostnames into to socket representation */
@@ -2423,24 +2521,42 @@ pcap_findalldevs_ex_remote(const char *source, struct pcap_rmtauth *auth, pcap_i
freeaddrinfo(addrinfo);
addrinfo = NULL;
- if (rpcap_doauth(sockctrl, &protocol_version, auth, errbuf) == -1)
+ if (uses_ssl)
+ {
+#ifdef HAVE_OPENSSL
+ ssl = ssl_promotion(0, sockctrl, errbuf, PCAP_ERRBUF_SIZE);
+ if (! ssl)
+ {
+ sock_close(sockctrl, NULL, 0);
+ return -1;
+ }
+#else
+ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "No TLS support");
+ sock_close(sockctrl, NULL, 0);;
+ return -1;
+#endif
+ }
+
+ if (rpcap_doauth(sockctrl, ssl, &protocol_version, auth, errbuf) == -1)
{
+#ifdef HAVE_OPENSSL
+ if (ssl) SSL_free(ssl); // Must be done before the socket is closed
+#endif
sock_close(sockctrl, NULL, 0);
return -1;
}
- active = 0;
}
/* RPCAP findalldevs command */
rpcap_createhdr(&header, protocol_version, RPCAP_MSG_FINDALLIF_REQ,
0, 0);
- if (sock_send(sockctrl, (char *)&header, sizeof(struct rpcap_header),
+ if (sock_send(sockctrl, ssl, (char *)&header, sizeof(struct rpcap_header),
errbuf, PCAP_ERRBUF_SIZE) < 0)
goto error_nodiscard;
/* Receive and process the reply message header. */
- if (rpcap_process_msg_header(sockctrl, protocol_version,
+ if (rpcap_process_msg_header(sockctrl, ssl, protocol_version,
RPCAP_MSG_FINDALLIF_REQ, &header, errbuf) == -1)
goto error_nodiscard;
@@ -2460,7 +2576,7 @@ pcap_findalldevs_ex_remote(const char *source, struct pcap_rmtauth *auth, pcap_i
tmpstring2[PCAP_BUF_SIZE] = 0;
/* receive the findalldevs structure from remote host */
- if (rpcap_recv(sockctrl, (char *)&findalldevs_if,
+ if (rpcap_recv(sockctrl, ssl, (char *)&findalldevs_if,
sizeof(struct rpcap_findalldevs_if), &plen, errbuf) == -1)
goto error;
@@ -2509,7 +2625,7 @@ pcap_findalldevs_ex_remote(const char *source, struct pcap_rmtauth *auth, pcap_i
}
/* Retrieve adapter name */
- if (rpcap_recv(sockctrl, tmpstring,
+ if (rpcap_recv(sockctrl, ssl, tmpstring,
findalldevs_if.namelen, &plen, errbuf) == -1)
goto error;
@@ -2542,7 +2658,7 @@ pcap_findalldevs_ex_remote(const char *source, struct pcap_rmtauth *auth, pcap_i
}
/* Retrieve adapter description */
- if (rpcap_recv(sockctrl, tmpstring,
+ if (rpcap_recv(sockctrl, ssl, tmpstring,
findalldevs_if.desclen, &plen, errbuf) == -1)
goto error;
@@ -2575,7 +2691,7 @@ pcap_findalldevs_ex_remote(const char *source, struct pcap_rmtauth *auth, pcap_i
struct rpcap_findalldevs_ifaddr ifaddr;
/* Retrieve the interface addresses */
- if (rpcap_recv(sockctrl, (char *)&ifaddr,
+ if (rpcap_recv(sockctrl, ssl, (char *)&ifaddr,
sizeof(struct rpcap_findalldevs_ifaddr),
&plen, errbuf) == -1)
goto error;
@@ -2649,13 +2765,16 @@ pcap_findalldevs_ex_remote(const char *source, struct pcap_rmtauth *auth, pcap_i
}
/* Discard the rest of the message. */
- if (rpcap_discard(sockctrl, plen, errbuf) == 1)
+ if (rpcap_discard(sockctrl, ssl, plen, errbuf) == 1)
goto error_nodiscard;
/* Control connection has to be closed only in case the remote machine is in passive mode */
if (!active)
{
/* DO not send RPCAP_CLOSE, since we did not open a pcap_t; no need to free resources */
+#ifdef HAVE_OPENSSL
+ if (ssl) SSL_free(ssl); // Has to be done before the socket is closed
+#endif
if (sock_close(sockctrl, errbuf, PCAP_ERRBUF_SIZE))
return -1;
}
@@ -2679,12 +2798,17 @@ error:
*
* Checks if all the data has been read; if not, discard the data in excess
*/
- (void) rpcap_discard(sockctrl, plen, NULL);
+ (void) rpcap_discard(sockctrl, ssl, plen, NULL);
error_nodiscard:
/* Control connection has to be closed only in case the remote machine is in passive mode */
if (!active)
+ {
+#ifdef HAVE_OPENSSL
+ if (ssl) SSL_free(ssl); // Has to be done before the socket is closed
+#endif
sock_close(sockctrl, NULL, 0);
+ }
/* To avoid inconsistencies in the number of sock_init() */
sock_cleanup();
@@ -2702,7 +2826,7 @@ error_nodiscard:
* to implement; we provide some APIs for it that work only with rpcap.
*/
-SOCKET pcap_remoteact_accept(const char *address, const char *port, const char *hostlist, char *connectinghost, struct pcap_rmtauth *auth, char *errbuf)
+SOCKET pcap_remoteact_accept(const char *address, const char *port, const char *hostlist, char *connectinghost, struct pcap_rmtauth *auth, int uses_ssl, char *errbuf)
{
/* socket-related variables */
struct addrinfo hints; /* temporary struct to keep settings needed to open the new socket */
@@ -2710,6 +2834,7 @@ SOCKET pcap_remoteact_accept(const char *address, const char *port, const char *
struct sockaddr_storage from; /* generic sockaddr_storage variable */
socklen_t fromlen; /* keeps the length of the sockaddr_storage variable */
SOCKET sockctrl; /* keeps the main socket identifier */
+ SSL *ssl = NULL; /* Optional SSL handler for sockctrl */
uint8 protocol_version; /* negotiated protocol version */
struct activehosts *temp, *prev; /* temp var needed to scan he host list chain */
@@ -2770,11 +2895,31 @@ SOCKET pcap_remoteact_accept(const char *address, const char *port, const char *
return (SOCKET)-2;
}
+ /* Promote to SSL early before any error message may be sent */
+ if (uses_ssl)
+ {
+#ifdef HAVE_OPENSSL
+ ssl = ssl_promotion(0, sockctrl, errbuf, PCAP_ERRBUF_SIZE);
+ if (! ssl)
+ {
+ sock_close(sockctrl, NULL, 0);
+ return (SOCKET)-1;
+ }
+#else
+ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "No TLS support");
+ sock_close(sockctrl, NULL, 0);
+ return (SOCKET)-1;
+#endif
+ }
+
/* Get the numeric for of the name of the connecting host */
if (getnameinfo((struct sockaddr *) &from, fromlen, connectinghost, RPCAP_HOSTLIST_SIZE, NULL, 0, NI_NUMERICHOST))
{
sock_geterror("getnameinfo(): ", errbuf, PCAP_ERRBUF_SIZE);
- rpcap_senderror(sockctrl, 0, PCAP_ERR_REMOTEACCEPT, errbuf, NULL);
+ rpcap_senderror(sockctrl, ssl, 0, PCAP_ERR_REMOTEACCEPT, errbuf, NULL);
+#ifdef HAVE_OPENSSL
+ if (ssl) SSL_free(ssl);
+#endif
sock_close(sockctrl, NULL, 0);
return (SOCKET)-1;
}
@@ -2782,7 +2927,10 @@ SOCKET pcap_remoteact_accept(const char *address, const char *port, const char *
/* checks if the connecting host is among the ones allowed */
if (sock_check_hostlist((char *)hostlist, RPCAP_HOSTLIST_SEP, &from, errbuf, PCAP_ERRBUF_SIZE) < 0)
{
- rpcap_senderror(sockctrl, 0, PCAP_ERR_REMOTEACCEPT, errbuf, NULL);
+ rpcap_senderror(sockctrl, ssl, 0, PCAP_ERR_REMOTEACCEPT, errbuf, NULL);
+#ifdef HAVE_OPENSSL
+ if (ssl) SSL_free(ssl);
+#endif
sock_close(sockctrl, NULL, 0);
return (SOCKET)-1;
}
@@ -2790,10 +2938,13 @@ SOCKET pcap_remoteact_accept(const char *address, const char *port, const char *
/*
* Send authentication to the remote machine.
*/
- if (rpcap_doauth(sockctrl, &protocol_version, auth, errbuf) == -1)
+ if (rpcap_doauth(sockctrl, ssl, &protocol_version, auth, errbuf) == -1)
{
/* Unrecoverable error. */
- rpcap_senderror(sockctrl, 0, PCAP_ERR_REMOTEACCEPT, errbuf, NULL);
+ rpcap_senderror(sockctrl, ssl, 0, PCAP_ERR_REMOTEACCEPT, errbuf, NULL);
+#ifdef HAVE_OPENSSL
+ if (ssl) SSL_free(ssl);
+#endif
sock_close(sockctrl, NULL, 0);
return (SOCKET)-3;
}
@@ -2830,13 +2981,17 @@ SOCKET pcap_remoteact_accept(const char *address, const char *port, const char *
{
pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
errno, "malloc() failed");
- rpcap_senderror(sockctrl, protocol_version, PCAP_ERR_REMOTEACCEPT, errbuf, NULL);
+ rpcap_senderror(sockctrl, ssl, protocol_version, PCAP_ERR_REMOTEACCEPT, errbuf, NULL);
+#ifdef HAVE_OPENSSL
+ if (ssl) SSL_free(ssl);
+#endif
sock_close(sockctrl, NULL, 0);
return (SOCKET)-1;
}
memcpy(&temp->host, &from, fromlen);
temp->sockctrl = sockctrl;
+ temp->ssl = ssl;
temp->protocol_version = protocol_version;
temp->next = NULL;
@@ -2883,7 +3038,7 @@ int pcap_remoteact_close(const char *host, char *errbuf)
* Don't check for errors, since we're
* just cleaning up.
*/
- if (sock_send(temp->sockctrl,
+ if (sock_send(temp->sockctrl, temp->ssl,
(char *)&header,
sizeof(struct rpcap_header), errbuf,
PCAP_ERRBUF_SIZE) < 0)
@@ -2892,12 +3047,18 @@ int pcap_remoteact_close(const char *host, char *errbuf)
* Let that error be the one we
* report.
*/
+#ifdef HAVE_OPENSSL
+ if (temp->ssl) SSL_free(temp->ssl);
+#endif
(void)sock_close(temp->sockctrl, NULL,
0);
status = -1;
}
else
{
+#ifdef HAVE_OPENSSL
+ if (temp->ssl) SSL_free(temp->ssl);
+#endif
if (sock_close(temp->sockctrl, errbuf,
PCAP_ERRBUF_SIZE) == -1)
status = -1;
@@ -2949,6 +3110,13 @@ void pcap_remoteact_cleanup(void)
sock_cleanup();
}
+# ifdef HAVE_OPENSSL
+ if (ssl_main)
+ {
+ SSL_free(ssl_main);
+ ssl_main = NULL;
+ }
+# endif
}
int pcap_remoteact_list(char *hostlist, char sep, int size, char *errbuf)
@@ -2998,11 +3166,11 @@ int pcap_remoteact_list(char *hostlist, char sep, int size, char *errbuf)
/*
* Receive the header of a message.
*/
-static int rpcap_recv_msg_header(SOCKET sock, struct rpcap_header *header, char *errbuf)
+static int rpcap_recv_msg_header(SOCKET sock, SSL *ssl, struct rpcap_header *header, char *errbuf)
{
int nrecv;
- nrecv = sock_recv(sock, (char *) header, sizeof(struct rpcap_header),
+ nrecv = sock_recv(sock, ssl, (char *) header, sizeof(struct rpcap_header),
SOCK_RECEIVEALL_YES|SOCK_EOF_IS_ERROR, errbuf,
PCAP_ERRBUF_SIZE);
if (nrecv == -1)
@@ -3018,7 +3186,7 @@ static int rpcap_recv_msg_header(SOCKET sock, struct rpcap_header *header, char
* Make sure the protocol version of a received message is what we were
* expecting.
*/
-static int rpcap_check_msg_ver(SOCKET sock, uint8 expected_ver, struct rpcap_header *header, char *errbuf)
+static int rpcap_check_msg_ver(SOCKET sock, SSL *ssl, uint8 expected_ver, struct rpcap_header *header, char *errbuf)
{
/*
* Did the server specify the version we negotiated?
@@ -3028,7 +3196,7 @@ static int rpcap_check_msg_ver(SOCKET sock, uint8 expected_ver, struct rpcap_hea
/*
* Discard the rest of the message.
*/
- if (rpcap_discard(sock, header->plen, errbuf) == -1)
+ if (rpcap_discard(sock, ssl, header->plen, errbuf) == -1)
return -1;
/*
@@ -3049,7 +3217,7 @@ static int rpcap_check_msg_ver(SOCKET sock, uint8 expected_ver, struct rpcap_hea
* Check the message type of a received message, which should either be
* the expected message type or RPCAP_MSG_ERROR.
*/
-static int rpcap_check_msg_type(SOCKET sock, uint8 request_type, struct rpcap_header *header, uint16 *errcode, char *errbuf)
+static int rpcap_check_msg_type(SOCKET sock, SSL *ssl, uint8 request_type, struct rpcap_header *header, uint16 *errcode, char *errbuf)
{
const char *request_type_string;
const char *msg_type_string;
@@ -3064,7 +3232,7 @@ static int rpcap_check_msg_type(SOCKET sock, uint8 request_type, struct rpcap_he
* Hand that error back to our caller.
*/
*errcode = ntohs(header->value);
- rpcap_msg_err(sock, header->plen, errbuf);
+ rpcap_msg_err(sock, ssl, header->plen, errbuf);
return -1;
}
@@ -3083,7 +3251,7 @@ static int rpcap_check_msg_type(SOCKET sock, uint8 request_type, struct rpcap_he
/*
* Discard the rest of the message.
*/
- if (rpcap_discard(sock, header->plen, errbuf) == -1)
+ if (rpcap_discard(sock, ssl, header->plen, errbuf) == -1)
return -1;
/*
@@ -3119,11 +3287,11 @@ static int rpcap_check_msg_type(SOCKET sock, uint8 request_type, struct rpcap_he
/*
* Receive and process the header of a message.
*/
-static int rpcap_process_msg_header(SOCKET sock, uint8 expected_ver, uint8 request_type, struct rpcap_header *header, char *errbuf)
+static int rpcap_process_msg_header(SOCKET sock, SSL *ssl, uint8 expected_ver, uint8 request_type, struct rpcap_header *header, char *errbuf)
{
uint16 errcode;
- if (rpcap_recv_msg_header(sock, header, errbuf) == -1)
+ if (rpcap_recv_msg_header(sock, ssl, header, errbuf) == -1)
{
/* Network error. */
return -1;
@@ -3132,13 +3300,13 @@ static int rpcap_process_msg_header(SOCKET sock, uint8 expected_ver, uint8 reque
/*
* Did the server specify the version we negotiated?
*/
- if (rpcap_check_msg_ver(sock, expected_ver, header, errbuf) == -1)
+ if (rpcap_check_msg_ver(sock, ssl, expected_ver, header, errbuf) == -1)
return -1;
/*
* Check the message type.
*/
- return rpcap_check_msg_type(sock, request_type, header,
+ return rpcap_check_msg_type(sock, ssl, request_type, header,
&errcode, errbuf);
}
@@ -3151,7 +3319,7 @@ static int rpcap_process_msg_header(SOCKET sock, uint8 expected_ver, uint8 reque
* Returns 0 on success, logs a message and returns -1 on a network
* error.
*/
-static int rpcap_recv(SOCKET sock, void *buffer, size_t toread, uint32 *plen, char *errbuf)
+static int rpcap_recv(SOCKET sock, SSL *ssl, void *buffer, size_t toread, uint32 *plen, char *errbuf)
{
int nread;
@@ -3161,7 +3329,7 @@ static int rpcap_recv(SOCKET sock, void *buffer, size_t toread, uint32 *plen, ch
pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Message payload is too short");
return -1;
}
- nread = sock_recv(sock, buffer, toread,
+ nread = sock_recv(sock, ssl, buffer, toread,
SOCK_RECEIVEALL_YES|SOCK_EOF_IS_ERROR, errbuf, PCAP_ERRBUF_SIZE);
if (nread == -1)
{
@@ -3174,7 +3342,7 @@ static int rpcap_recv(SOCKET sock, void *buffer, size_t toread, uint32 *plen, ch
/*
* This handles the RPCAP_MSG_ERROR message.
*/
-static void rpcap_msg_err(SOCKET sockctrl, uint32 plen, char *remote_errbuf)
+static void rpcap_msg_err(SOCKET sockctrl, SSL *ssl, uint32 plen, char *remote_errbuf)
{
char errbuf[PCAP_ERRBUF_SIZE];
@@ -3184,7 +3352,7 @@ static void rpcap_msg_err(SOCKET sockctrl, uint32 plen, char *remote_errbuf)
* Message is too long; just read as much of it as we
* can into the buffer provided, and discard the rest.
*/
- if (sock_recv(sockctrl, remote_errbuf, PCAP_ERRBUF_SIZE - 1,
+ if (sock_recv(sockctrl, ssl, remote_errbuf, PCAP_ERRBUF_SIZE - 1,
SOCK_RECEIVEALL_YES|SOCK_EOF_IS_ERROR, errbuf,
PCAP_ERRBUF_SIZE) == -1)
{
@@ -3201,7 +3369,7 @@ static void rpcap_msg_err(SOCKET sockctrl, uint32 plen, char *remote_errbuf)
/*
* Throw away the rest.
*/
- (void)rpcap_discard(sockctrl, plen - (PCAP_ERRBUF_SIZE - 1), remote_errbuf);
+ (void)rpcap_discard(sockctrl, ssl, plen - (PCAP_ERRBUF_SIZE - 1), remote_errbuf);
}
else if (plen == 0)
{
@@ -3210,7 +3378,7 @@ static void rpcap_msg_err(SOCKET sockctrl, uint32 plen, char *remote_errbuf)
}
else
{
- if (sock_recv(sockctrl, remote_errbuf, plen,
+ if (sock_recv(sockctrl, ssl, remote_errbuf, plen,
SOCK_RECEIVEALL_YES|SOCK_EOF_IS_ERROR, errbuf,
PCAP_ERRBUF_SIZE) == -1)
{
@@ -3232,11 +3400,11 @@ static void rpcap_msg_err(SOCKET sockctrl, uint32 plen, char *remote_errbuf)
* Returns 0 on success, logs a message and returns -1 on a network
* error.
*/
-static int rpcap_discard(SOCKET sock, uint32 len, char *errbuf)
+static int rpcap_discard(SOCKET sock, SSL *ssl, uint32 len, char *errbuf)
{
if (len != 0)
{
- if (sock_discard(sock, len, errbuf, PCAP_ERRBUF_SIZE) == -1)
+ if (sock_discard(sock, ssl, len, errbuf, PCAP_ERRBUF_SIZE) == -1)
{
// Network error.
return -1;
@@ -3249,7 +3417,7 @@ static int rpcap_discard(SOCKET sock, uint32 len, char *errbuf)
* Read bytes into the pcap_t's buffer until we have the specified
* number of bytes read or we get an error or interrupt indication.
*/
-static int rpcap_read_packet_msg(SOCKET sock, pcap_t *p, size_t size)
+static int rpcap_read_packet_msg(struct pcap_rpcap const *rp, pcap_t *p, size_t size)
{
u_char *bp;
int cc;
@@ -3268,9 +3436,10 @@ static int rpcap_read_packet_msg(SOCKET sock, pcap_t *p, size_t size)
* We haven't read all of the packet header yet.
* Read what remains, which could be all of it.
*/
- bytes_read = sock_recv(sock, bp, size - cc,
+ bytes_read = sock_recv(rp->rmt_sockdata, rp->data_ssl, bp, size - cc,
SOCK_RECEIVEALL_NO|SOCK_EOF_IS_ERROR, p->errbuf,
PCAP_ERRBUF_SIZE);
+
if (bytes_read == -1)
{
/*
diff --git a/pcap.c b/pcap.c
index f053811b..6fe8e16a 100644
--- a/pcap.c
+++ b/pcap.c
@@ -1599,7 +1599,8 @@ pcap_parse_source(const char *source, char **schemep, char **userinfop,
*
* XXX - %-escaping?
*/
- if (pcap_strcasecmp(scheme, "rpcap") == 0 &&
+ if ((pcap_strcasecmp(scheme, "rpcap") == 0 ||
+ pcap_strcasecmp(scheme, "rpcaps") == 0) &&
strchr(colonp + 3, '/') == NULL) {
/*
* Local device.
@@ -1869,8 +1870,8 @@ pcap_createsrcstr(char *source, int type, const char *host, const char *port,
}
int
-pcap_parsesrcstr(const char *source, int *type, char *host, char *port,
- char *name, char *errbuf)
+pcap_parsesrcstr_ex(const char *source, int *type, char *host, char *port,
+ char *name, unsigned char *uses_ssl, char *errbuf)
{
char *scheme, *tmpuserinfo, *tmphost, *tmpport, *tmppath;
@@ -1881,6 +1882,8 @@ pcap_parsesrcstr(const char *source, int *type, char *host, char *port,
*port = '\0';
if (name)
*name = '\0';
+ if (uses_ssl)
+ *uses_ssl = 0;
/* Parse the source string */
if (pcap_parse_source(source, &scheme, &tmpuserinfo, &tmphost,
@@ -1906,12 +1909,20 @@ pcap_parsesrcstr(const char *source, int *type, char *host, char *port,
return (0);
}
- if (strcmp(scheme, "rpcap") == 0) {
+ int is_rpcap = 0;
+ if (strcmp(scheme, "rpcaps") == 0) {
+ is_rpcap = 1;
+ if (uses_ssl) *uses_ssl = 1;
+ } else if (strcmp(scheme, "rpcap") == 0) {
+ is_rpcap = 1;
+ }
+
+ if (is_rpcap) {
/*
- * rpcap://
+ * rpcap[s]://
*
* pcap_parse_source() has already handled the case of
- * rpcap://device
+ * rpcap[s]://device
*/
if (host && tmphost) {
if (tmpuserinfo)
@@ -1965,6 +1976,13 @@ pcap_parsesrcstr(const char *source, int *type, char *host, char *port,
free(scheme);
return (0);
}
+
+int
+pcap_parsesrcstr(const char *source, int *type, char *host, char *port,
+ char *name, char *errbuf)
+{
+ return pcap_parsesrcstr_ex(source, type, host, port, name, NULL, errbuf);
+}
#endif
pcap_t *
diff --git a/pcap/pcap.h b/pcap/pcap.h
index 8b5ecba5..571c88c0 100644
--- a/pcap/pcap.h
+++ b/pcap/pcap.h
@@ -631,6 +631,9 @@ PCAP_API const char *pcap_lib_version(void);
* - rpcap:// [lists all local adapters]
* - rpcap://host:port/ [lists the devices available on a remote host]
*
+ * In all the above, "rpcaps://" can be substituted for "rpcap://" to enable
+ * SSL (if it has been compiled in).
+ *
* Referring to the 'host' and 'port' parameters, they can be either numeric or literal. Since
* IPv6 is fully supported, these are the allowed formats:
*
@@ -947,7 +950,7 @@ PCAP_API struct pcap_samp *pcap_setsampling(pcap_t *p);
PCAP_API SOCKET pcap_remoteact_accept(const char *address, const char *port,
const char *hostlist, char *connectinghost,
- struct pcap_rmtauth *auth, char *errbuf);
+ struct pcap_rmtauth *auth, int uses_ssl, char *errbuf);
PCAP_API int pcap_remoteact_list(char *hostlist, char sep, int size,
char *errbuf);
PCAP_API int pcap_remoteact_close(const char *host, char *errbuf);
diff --git a/rpcap-protocol.c b/rpcap-protocol.c
index 692f7c5c..0cdc0ba3 100644
--- a/rpcap-protocol.c
+++ b/rpcap-protocol.c
@@ -61,6 +61,8 @@
*
* \param sock: the socket we are currently using.
*
+ * \param ssl: if compiled with openssl, the optional ssl handler to use with the above socket.
+ *
* \param ver: the protocol version we want to put in the reply.
*
* \param errcode: a integer which tells the other party the type of error
@@ -78,7 +80,7 @@
* error message is returned in the 'errbuf' variable.
*/
int
-rpcap_senderror(SOCKET sock, uint8 ver, unsigned short errcode, const char *error, char *errbuf)
+rpcap_senderror(SOCKET sock, SSL *ssl, uint8 ver, unsigned short errcode, const char *error, 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 */
@@ -99,7 +101,7 @@ rpcap_senderror(SOCKET sock, uint8 ver, unsigned short errcode, const char *erro
RPCAP_NETBUF_SIZE, SOCKBUF_BUFFERIZE, errbuf, PCAP_ERRBUF_SIZE))
return -1;
- if (sock_send(sock, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) < 0)
+ if (sock_send(sock, ssl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) < 0)
return -1;
return 0;
diff --git a/rpcap-protocol.h b/rpcap-protocol.h
index 7598a0ae..ad66b755 100644
--- a/rpcap-protocol.h
+++ b/rpcap-protocol.h
@@ -445,9 +445,10 @@ struct rpcap_sampling
*********************************************************/
#include "sockutils.h"
+#include "sslutils.h"
extern void rpcap_createhdr(struct rpcap_header *header, uint8 ver, uint8 type, uint16 value, uint32 length);
extern const char *rpcap_msg_type_string(uint8 type);
-extern int rpcap_senderror(SOCKET sock, uint8 ver, uint16 errcode, const char *error, char *errbuf);
+extern int rpcap_senderror(SOCKET sock, SSL *ssl, uint8 ver, uint16 errcode, const char *error, char *errbuf);
#endif
diff --git a/rpcapd/Makefile.in b/rpcapd/Makefile.in
index 1b530d5a..659f0a7c 100644
--- a/rpcapd/Makefile.in
+++ b/rpcapd/Makefile.in
@@ -84,7 +84,7 @@ SRC = daemon.c \
log-stderr.c \
rpcapd.c
-OBJ = $(SRC:.c=.o) ../rpcap-protocol.o ../sockutils.o ../fmtutils.o
+OBJ = $(SRC:.c=.o) ../rpcap-protocol.o ../sockutils.o ../fmtutils.o ../sslutils.o
PUBHDR =
HDR = $(PUBHDR) log.h
diff --git a/rpcapd/daemon.c b/rpcapd/daemon.c
index e30eeef1..12b555ec 100644
--- a/rpcapd/daemon.c
+++ b/rpcapd/daemon.c
@@ -64,6 +64,11 @@
#include "daemon.h"
#include "log.h"
+#ifdef HAVE_OPENSSL
+#include <openssl/ssl.h>
+#include "sslutils.h"
+#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 */
@@ -73,6 +78,7 @@ struct daemon_slpars
{
SOCKET sockctrl_in; //!< SOCKET ID of the input side of the control connection
SOCKET sockctrl_out; //!< SOCKET ID of the output side of the control connection
+ SSL *ssl; //!< Optional SSL handler for the controlling sockets
uint8 protocol_version; //!< negotiated protocol version
int isactive; //!< Not null if the daemon has to run in active mode
int nullAuthAllowed; //!< '1' if we permit NULL authentication, '0' otherwise
@@ -84,6 +90,7 @@ struct daemon_slpars
struct session {
SOCKET sockctrl_out;
SOCKET sockdata;
+ SSL *ctrl_ssl, *data_ssl; // optional SSL handlers for sockctrl_out and sockdata.
uint8 protocol_version;
pcap_t *fp;
unsigned int TotCapt;
@@ -107,18 +114,18 @@ struct thread_handle {
};
// Locally defined functions
-static int daemon_msg_err(SOCKET sockctrl_in, uint32 plen);
+static int daemon_msg_err(SOCKET sockctrl_in, SSL *, uint32 plen);
static int daemon_msg_auth_req(struct daemon_slpars *pars, uint32 plen);
static int daemon_AuthUserPwd(char *username, char *password, char *errbuf);
static int daemon_msg_findallif_req(struct daemon_slpars *pars, uint32 plen);
static int daemon_msg_open_req(struct daemon_slpars *pars, uint32 plen, char *source, size_t sourcelen);
-static int daemon_msg_startcap_req(struct daemon_slpars *pars, uint32 plen, struct thread_handle *threaddata, char *source, struct session **sessionp, struct rpcap_sampling *samp_param);
+static int daemon_msg_startcap_req(struct daemon_slpars *pars, uint32 plen, struct thread_handle *threaddata, char *source, struct session **sessionp, struct rpcap_sampling *samp_param, int uses_ssl);
static int daemon_msg_endcap_req(struct daemon_slpars *pars, struct session *session, struct thread_handle *threaddata);
static int daemon_msg_updatefilter_req(struct daemon_slpars *pars, struct session *session, uint32 plen);
-static int daemon_unpackapplyfilter(SOCKET sockctrl_in, struct session *session, uint32 *plenp, char *errbuf);
+static int daemon_unpackapplyfilter(SOCKET sockctrl_in, SSL *, struct session *session, uint32 *plenp, char *errbuf);
static int daemon_msg_stats_req(struct daemon_slpars *pars, struct session *session, uint32 plen, struct pcap_stat *stats, unsigned int svrcapt);
@@ -131,12 +138,13 @@ static unsigned __stdcall daemon_thrdatamain(void *ptr);
static void *daemon_thrdatamain(void *ptr);
#endif
-static int rpcapd_recv_msg_header(SOCKET sock, struct rpcap_header *headerp);
-static int rpcapd_recv(SOCKET sock, char *buffer, size_t toread, uint32 *plen, char *errmsgbuf);
-static int rpcapd_discard(SOCKET sock, uint32 len);
+static int rpcapd_recv_msg_header(SOCKET sock, SSL *, struct rpcap_header *headerp);
+static int rpcapd_recv(SOCKET sock, SSL *, char *buffer, size_t toread, uint32 *plen, char *errmsgbuf);
+static int rpcapd_discard(SOCKET sock, SSL *, uint32 len);
+static void session_close(struct session *);
int
-daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nullAuthAllowed)
+daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, SSL *ssl, int isactive, int nullAuthAllowed, int uses_ssl)
{
struct daemon_slpars pars; // service loop parameters
char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed
@@ -167,6 +175,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu
// Set parameters structure
pars.sockctrl_in = sockctrl_in;
pars.sockctrl_out = sockctrl_out;
+ pars.ssl = ssl;
pars.protocol_version = 0; // not yet known
pars.isactive = isactive; // active mode
pars.nullAuthAllowed = nullAuthAllowed;
@@ -217,7 +226,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu
if (retval == -1)
{
sock_geterror("select failed: ", errmsgbuf, PCAP_ERRBUF_SIZE);
- if (rpcap_senderror(pars.sockctrl_out, 0, PCAP_ERR_NETW, errmsgbuf, errbuf) == -1)
+ if (rpcap_senderror(pars.sockctrl_out, pars.ssl, 0, PCAP_ERR_NETW, errmsgbuf, errbuf) == -1)
rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
goto end;
}
@@ -226,7 +235,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu
// So, this was a fake connection. Drop it down
if (retval == 0)
{
- if (rpcap_senderror(pars.sockctrl_out, 0, PCAP_ERR_INITTIMEOUT, "The RPCAP initial timeout has expired", errbuf) == -1)
+ if (rpcap_senderror(pars.sockctrl_out, pars.ssl, 0, PCAP_ERR_INITTIMEOUT, "The RPCAP initial timeout has expired", errbuf) == -1)
rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
goto end;
}
@@ -235,7 +244,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu
//
// Read the message header from the client.
//
- nrecv = rpcapd_recv_msg_header(pars.sockctrl_in, &header);
+ nrecv = rpcapd_recv_msg_header(pars.sockctrl_in, pars.ssl, &header);
if (nrecv == -1)
{
// Fatal error.
@@ -291,7 +300,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu
//
reply_version = RPCAP_MAX_VERSION;
}
- if (rpcap_senderror(pars.sockctrl_out, reply_version,
+ if (rpcap_senderror(pars.sockctrl_out, pars.ssl, reply_version,
PCAP_ERR_WRONGVER, "RPCAP version number mismatch",
errbuf) == -1)
{
@@ -301,7 +310,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu
}
// Discard the rest of the message.
- if (rpcapd_discard(pars.sockctrl_in, plen) == -1)
+ if (rpcapd_discard(pars.sockctrl_in, pars.ssl, plen) == -1)
{
// Network error.
goto end;
@@ -345,7 +354,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu
// Discard the rest of the message, if
// there is anything more.
//
- (void)rpcapd_discard(pars.sockctrl_in, plen);
+ (void)rpcapd_discard(pars.sockctrl_in, pars.ssl, plen);
// We're done with this client.
goto end;
@@ -357,7 +366,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu
// an error message rather than a "let
// me log in" message, indicating that
// we're not allowed to connect to them?
- (void)daemon_msg_err(pars.sockctrl_in, plen);
+ (void)daemon_msg_err(pars.sockctrl_in, pars.ssl, plen);
goto end;
case RPCAP_MSG_FINDALLIF_REQ:
@@ -380,7 +389,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu
{
pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Message of type %u sent before authentication was completed", header.type);
}
- if (rpcap_senderror(pars.sockctrl_out,
+ if (rpcap_senderror(pars.sockctrl_out, pars.ssl,
pars.protocol_version, PCAP_ERR_WRONGMSG,
errmsgbuf, errbuf) == -1)
{
@@ -388,7 +397,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu
goto end;
}
// Discard the rest of the message.
- if (rpcapd_discard(pars.sockctrl_in, plen) == -1)
+ if (rpcapd_discard(pars.sockctrl_in, pars.ssl, plen) == -1)
{
// Network error.
goto end;
@@ -416,7 +425,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu
{
pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Server-to-client message of type %u received from client", header.type);
}
- if (rpcap_senderror(pars.sockctrl_out,
+ if (rpcap_senderror(pars.sockctrl_out, pars.ssl,
pars.protocol_version, PCAP_ERR_WRONGMSG,
errmsgbuf, errbuf) == -1)
{
@@ -424,7 +433,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu
goto end;
}
// Discard the rest of the message.
- if (rpcapd_discard(pars.sockctrl_in, plen) == -1)
+ if (rpcapd_discard(pars.sockctrl_in, pars.ssl, plen) == -1)
{
// Fatal error.
goto end;
@@ -436,7 +445,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu
// Unknown message type.
//
pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Unknown message type %u", header.type);
- if (rpcap_senderror(pars.sockctrl_out,
+ if (rpcap_senderror(pars.sockctrl_out, pars.ssl,
pars.protocol_version, PCAP_ERR_WRONGMSG,
errmsgbuf, errbuf) == -1)
{
@@ -444,7 +453,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu
goto end;
}
// Discard the rest of the message.
- if (rpcapd_discard(pars.sockctrl_in, plen) == -1)
+ if (rpcapd_discard(pars.sockctrl_in, pars.ssl, plen) == -1)
{
// Fatal error.
goto end;
@@ -496,7 +505,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu
if (retval == -1)
{
sock_geterror("select failed: ", errmsgbuf, PCAP_ERRBUF_SIZE);
- if (rpcap_senderror(pars.sockctrl_out,
+ if (rpcap_senderror(pars.sockctrl_out, pars.ssl,
pars.protocol_version, PCAP_ERR_NETW,
errmsgbuf, errbuf) == -1)
rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
@@ -507,7 +516,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu
// So, this was a fake connection. Drop it down
if (retval == 0)
{
- if (rpcap_senderror(pars.sockctrl_out,
+ if (rpcap_senderror(pars.sockctrl_out, pars.ssl,
pars.protocol_version,
PCAP_ERR_INITTIMEOUT,
"The RPCAP initial timeout has expired",
@@ -520,7 +529,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu
//
// Read the message header from the client.
//
- nrecv = rpcapd_recv_msg_header(pars.sockctrl_in, &header);
+ nrecv = rpcapd_recv_msg_header(pars.sockctrl_in, pars.ssl, &header);
if (nrecv == -1)
{
// Fatal error.
@@ -547,7 +556,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu
// so they don't reject it as having the wrong
// version.
//
- if (rpcap_senderror(pars.sockctrl_out,
+ if (rpcap_senderror(pars.sockctrl_out, pars.ssl,
header.ver, PCAP_ERR_WRONGVER,
"RPCAP version in message isn't the negotiated version",
errbuf) == -1)
@@ -558,7 +567,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu
}
// Discard the rest of the message.
- (void)rpcapd_discard(pars.sockctrl_in, plen);
+ (void)rpcapd_discard(pars.sockctrl_in, pars.ssl, plen);
// Give up on them.
goto end;
}
@@ -567,7 +576,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu
{
case RPCAP_MSG_ERROR: // The other endpoint reported an error
{
- (void)daemon_msg_err(pars.sockctrl_in, plen);
+ (void)daemon_msg_err(pars.sockctrl_in, pars.ssl, plen);
// Do nothing; just exit; the error code is already into the errbuf
// XXX - actually exit....
break;
@@ -612,7 +621,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu
{
// They never told us what device
// to capture on!
- if (rpcap_senderror(pars.sockctrl_out,
+ if (rpcap_senderror(pars.sockctrl_out, pars.ssl,
pars.protocol_version,
PCAP_ERR_STARTCAPTURE,
"No capture device was specified",
@@ -623,14 +632,14 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu
rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
goto end;
}
- if (rpcapd_discard(pars.sockctrl_in, plen) == -1)
+ if (rpcapd_discard(pars.sockctrl_in, pars.ssl, plen) == -1)
{
goto end;
}
break;
}
- if (daemon_msg_startcap_req(&pars, plen, &threaddata, source, &session, &samp_param) == -1)
+ if (daemon_msg_startcap_req(&pars, plen, &threaddata, source, &session, &samp_param, uses_ssl) == -1)
{
// Fatal error; a message has
// been logged, so just give up.
@@ -652,7 +661,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu
}
else
{
- if (rpcap_senderror(pars.sockctrl_out,
+ if (rpcap_senderror(pars.sockctrl_out, pars.ssl,
pars.protocol_version,
PCAP_ERR_UPDATEFILTER,
"Device not opened. Cannot update filter",
@@ -719,7 +728,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu
}
else
{
- rpcap_senderror(pars.sockctrl_out,
+ rpcap_senderror(pars.sockctrl_out, pars.ssl,
pars.protocol_version,
PCAP_ERR_ENDCAPTURE,
"Device not opened. Cannot close the capture",
@@ -746,7 +755,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu
// get to reauthenticate.
//
rpcapd_log(LOGPRIO_INFO, "The client sent an RPCAP_MSG_AUTH_REQ message after authentication was completed");
- if (rpcap_senderror(pars.sockctrl_out,
+ if (rpcap_senderror(pars.sockctrl_out, pars.ssl,
pars.protocol_version,
PCAP_ERR_WRONGMSG,
"RPCAP_MSG_AUTH_REQ request sent after authentication was completed",
@@ -756,7 +765,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu
goto end;
}
// Discard the rest of the message.
- if (rpcapd_discard(pars.sockctrl_in, plen) == -1)
+ if (rpcapd_discard(pars.sockctrl_in, pars.ssl, plen) == -1)
{
// Fatal error.
goto end;
@@ -786,7 +795,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu
rpcapd_log(LOGPRIO_INFO, "The client sent a server-to-client message of type %u", header.type);
pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Server-to-client message of type %u received from client", header.type);
}
- if (rpcap_senderror(pars.sockctrl_out,
+ if (rpcap_senderror(pars.sockctrl_out, pars.ssl,
pars.protocol_version, PCAP_ERR_WRONGMSG,
errmsgbuf, errbuf) == -1)
{
@@ -794,7 +803,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu
goto end;
}
// Discard the rest of the message.
- if (rpcapd_discard(pars.sockctrl_in, plen) == -1)
+ if (rpcapd_discard(pars.sockctrl_in, pars.ssl, plen) == -1)
{
// Fatal error.
goto end;
@@ -807,7 +816,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu
//
rpcapd_log(LOGPRIO_INFO, "The client sent a message of type %u", header.type);
pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Unknown message type %u", header.type);
- if (rpcap_senderror(pars.sockctrl_out,
+ if (rpcap_senderror(pars.sockctrl_out, pars.ssl,
pars.protocol_version, PCAP_ERR_WRONGMSG,
errbuf, errmsgbuf) == -1)
{
@@ -815,7 +824,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu
goto end;
}
// Discard the rest of the message.
- if (rpcapd_discard(pars.sockctrl_in, plen) == -1)
+ if (rpcapd_discard(pars.sockctrl_in, pars.ssl, plen) == -1)
{
// Fatal error.
goto end;
@@ -865,12 +874,8 @@ end:
#endif
threaddata.have_thread = 0;
}
- if (session->sockdata)
- {
- sock_close(session->sockdata, NULL, 0);
- session->sockdata = 0;
- }
- pcap_close(session->fp);
+
+ session_close(session);
free(session);
session = NULL;
}
@@ -886,7 +891,7 @@ end:
* This handles the RPCAP_MSG_ERR message.
*/
static int
-daemon_msg_err(SOCKET sockctrl_in, uint32 plen)
+daemon_msg_err(SOCKET sockctrl_in, SSL *ssl, uint32 plen)
{
char errbuf[PCAP_ERRBUF_SIZE];
char remote_errbuf[PCAP_ERRBUF_SIZE];
@@ -897,7 +902,7 @@ daemon_msg_err(SOCKET sockctrl_in, uint32 plen)
* Message is too long; just read as much of it as we
* can into the buffer provided, and discard the rest.
*/
- if (sock_recv(sockctrl_in, remote_errbuf, PCAP_ERRBUF_SIZE - 1,
+ if (sock_recv(sockctrl_in, ssl, remote_errbuf, PCAP_ERRBUF_SIZE - 1,
SOCK_RECEIVEALL_YES|SOCK_EOF_IS_ERROR, errbuf,
PCAP_ERRBUF_SIZE) == -1)
{
@@ -905,7 +910,7 @@ daemon_msg_err(SOCKET sockctrl_in, uint32 plen)
rpcapd_log(LOGPRIO_ERROR, "Read from client failed: %s", errbuf);
return -1;
}
- if (rpcapd_discard(sockctrl_in, plen - (PCAP_ERRBUF_SIZE - 1)) == -1)
+ if (rpcapd_discard(sockctrl_in, ssl, plen - (PCAP_ERRBUF_SIZE - 1)) == -1)
{
// Network error.
return -1;
@@ -923,7 +928,7 @@ daemon_msg_err(SOCKET sockctrl_in, uint32 plen)
}
else
{
- if (sock_recv(sockctrl_in, remote_errbuf, plen,
+ if (sock_recv(sockctrl_in, ssl, remote_errbuf, plen,
SOCK_RECEIVEALL_YES|SOCK_EOF_IS_ERROR, errbuf,
PCAP_ERRBUF_SIZE) == -1)
{
@@ -973,7 +978,7 @@ daemon_msg_auth_req(struct daemon_slpars *pars, uint32 plen)
int status;
struct rpcap_auth auth; // RPCAP authentication header
- status = rpcapd_recv(pars->sockctrl_in, (char *) &auth, sizeof(struct rpcap_auth), &plen, errmsgbuf);
+ status = rpcapd_recv(pars->sockctrl_in, pars->ssl, (char *) &auth, sizeof(struct rpcap_auth), &plen, errmsgbuf);
if (status == -1)
{
return -1;
@@ -1009,7 +1014,7 @@ daemon_msg_auth_req(struct daemon_slpars *pars, uint32 plen)
PCAP_ERRBUF_SIZE, errno, "malloc() failed");
goto error;
}
- status = rpcapd_recv(pars->sockctrl_in, username, usernamelen, &plen, errmsgbuf);
+ status = rpcapd_recv(pars->sockctrl_in, pars->ssl, username, usernamelen, &plen, errmsgbuf);
if (status == -1)
{
free(username);
@@ -1031,7 +1036,7 @@ daemon_msg_auth_req(struct daemon_slpars *pars, uint32 plen)
free(username);
goto error;
}
- status = rpcapd_recv(pars->sockctrl_in, passwd, passwdlen, &plen, errmsgbuf);
+ status = rpcapd_recv(pars->sockctrl_in, pars->ssl, passwd, passwdlen, &plen, errmsgbuf);
if (status == -1)
{
free(username);
@@ -1054,7 +1059,7 @@ daemon_msg_auth_req(struct daemon_slpars *pars, uint32 plen)
//
free(username);
free(passwd);
- if (rpcap_senderror(pars->sockctrl_out,
+ if (rpcap_senderror(pars->sockctrl_out, pars->ssl,
pars->protocol_version,
PCAP_ERR_AUTH, errmsgbuf, errbuf) == -1)
{
@@ -1091,7 +1096,7 @@ daemon_msg_auth_req(struct daemon_slpars *pars, uint32 plen)
rpcap_createhdr(&header, pars->protocol_version, RPCAP_MSG_AUTH_REPLY, 0, 0);
// Send the ok message back
- if (sock_send(pars->sockctrl_out, (char *) &header, sizeof (struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE) == -1)
+ if (sock_send(pars->sockctrl_out, pars->ssl, (char *) &header, sizeof (struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE) == -1)
{
// That failed; log a messsage and give up.
rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
@@ -1099,7 +1104,7 @@ daemon_msg_auth_req(struct daemon_slpars *pars, uint32 plen)
}
// Check if all the data has been read; if not, discard the data in excess
- if (rpcapd_discard(pars->sockctrl_in, plen) == -1)
+ if (rpcapd_discard(pars->sockctrl_in, pars->ssl, plen) == -1)
{
return -1;
}
@@ -1107,7 +1112,7 @@ daemon_msg_auth_req(struct daemon_slpars *pars, uint32 plen)
return 0;
error:
- if (rpcap_senderror(pars->sockctrl_out, pars->protocol_version,
+ if (rpcap_senderror(pars->sockctrl_out, pars->ssl, pars->protocol_version,
PCAP_ERR_AUTH, errmsgbuf, errbuf) == -1)
{
// That failed; log a message and give up.
@@ -1117,7 +1122,7 @@ error:
error_noreply:
// Check if all the data has been read; if not, discard the data in excess
- if (rpcapd_discard(pars->sockctrl_in, plen) == -1)
+ if (rpcapd_discard(pars->sockctrl_in, pars->ssl, plen) == -1)
{
return -1;
}
@@ -1262,7 +1267,7 @@ daemon_msg_findallif_req(struct daemon_slpars *pars, uint32 plen)
uint16 nif = 0; // counts the number of interface listed
// Discard the rest of the message; there shouldn't be any payload.
- if (rpcapd_discard(pars->sockctrl_in, plen) == -1)
+ if (rpcapd_discard(pars->sockctrl_in, pars->ssl, plen) == -1)
{
// Network error.
return -1;
@@ -1274,7 +1279,7 @@ daemon_msg_findallif_req(struct daemon_slpars *pars, uint32 plen)
if (alldevs == NULL)
{
- if (rpcap_senderror(pars->sockctrl_out, pars->protocol_version,
+ if (rpcap_senderror(pars->sockctrl_out, pars->ssl, pars->protocol_version,
PCAP_ERR_NOREMOTEIF,
"No interfaces found! Make sure libpcap/WinPcap is properly installed"
" and you have the right to access to the remote device.",
@@ -1428,7 +1433,7 @@ daemon_msg_findallif_req(struct daemon_slpars *pars, uint32 plen)
pcap_freealldevs(alldevs);
// Send a final command that says "now send it!"
- if (sock_send(pars->sockctrl_out, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
+ if (sock_send(pars->sockctrl_out, pars->ssl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
{
rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
return -1;
@@ -1440,7 +1445,7 @@ error:
if (alldevs)
pcap_freealldevs(alldevs);
- if (rpcap_senderror(pars->sockctrl_out, pars->protocol_version,
+ if (rpcap_senderror(pars->sockctrl_out, pars->ssl, pars->protocol_version,
PCAP_ERR_FINDALLIF, errmsgbuf, errbuf) == -1)
{
rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
@@ -1470,7 +1475,7 @@ daemon_msg_open_req(struct daemon_slpars *pars, uint32 plen, char *source, size_
goto error;
}
- nread = sock_recv(pars->sockctrl_in, source, plen,
+ nread = sock_recv(pars->sockctrl_in, pars->ssl, source, plen,
SOCK_RECEIVEALL_YES|SOCK_EOF_IS_ERROR, errbuf, PCAP_ERRBUF_SIZE);
if (nread == -1)
{
@@ -1513,7 +1518,7 @@ daemon_msg_open_req(struct daemon_slpars *pars, uint32 plen, char *source, size_
pcap_close(fp);
// Send the reply.
- if (sock_send(pars->sockctrl_out, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
+ if (sock_send(pars->sockctrl_out, pars->ssl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
{
rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
return -1;
@@ -1521,7 +1526,7 @@ daemon_msg_open_req(struct daemon_slpars *pars, uint32 plen, char *source, size_
return 0;
error:
- if (rpcap_senderror(pars->sockctrl_out, pars->protocol_version,
+ if (rpcap_senderror(pars->sockctrl_out, pars->ssl, pars->protocol_version,
PCAP_ERR_OPEN, errmsgbuf, errbuf) == -1)
{
// That failed; log a message and give up.
@@ -1530,7 +1535,7 @@ error:
}
// Check if all the data has been read; if not, discard the data in excess
- if (rpcapd_discard(pars->sockctrl_in, plen) == -1)
+ if (rpcapd_discard(pars->sockctrl_in, pars->ssl, plen) == -1)
{
return -1;
}
@@ -1542,7 +1547,7 @@ error:
to discard excess data in the message, if present)
*/
static int
-daemon_msg_startcap_req(struct daemon_slpars *pars, uint32 plen, struct thread_handle *threaddata, char *source, struct session **sessionp, struct rpcap_sampling *samp_param _U_)
+daemon_msg_startcap_req(struct daemon_slpars *pars, uint32 plen, struct thread_handle *threaddata, char *source, struct session **sessionp, struct rpcap_sampling *samp_param _U_, int uses_ssl)
{
char errbuf[PCAP_ERRBUF_SIZE]; // buffer for network errors
char errmsgbuf[PCAP_ERRBUF_SIZE]; // buffer for errors to send to the client
@@ -1572,7 +1577,7 @@ daemon_msg_startcap_req(struct daemon_slpars *pars, uint32 plen, struct thread_h
addrinfo = NULL;
- status = rpcapd_recv(pars->sockctrl_in, (char *) &startcapreq,
+ status = rpcapd_recv(pars->sockctrl_in, pars->ssl, (char *) &startcapreq,
sizeof(struct rpcap_startcapreq), &plen, errmsgbuf);
if (status == -1)
{
@@ -1585,6 +1590,15 @@ daemon_msg_startcap_req(struct daemon_slpars *pars, uint32 plen, struct thread_h
startcapreq.flags = ntohs(startcapreq.flags);
+ // Check that the client does not ask for UDP is the server has been asked
+ // to enforce encryption, as SSL is not supported yet with UDP:
+ if (uses_ssl && (startcapreq.flags & RPCAP_STARTCAPREQ_FLAG_DGRAM))
+ {
+ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "SSL not supported with UDP forward of remote packets");
+ goto error;
+ }
+
// Create a session structure
session = malloc(sizeof(struct session));
if (session == NULL)
@@ -1593,6 +1607,8 @@ daemon_msg_startcap_req(struct daemon_slpars *pars, uint32 plen, struct thread_h
goto error;
}
+ session->ctrl_ssl = session->data_ssl = NULL;
+
// Open the selected device
if ((session->fp = pcap_open_live(source,
ntohl(startcapreq.snaplen),
@@ -1687,10 +1703,11 @@ daemon_msg_startcap_req(struct daemon_slpars *pars, uint32 plen, struct thread_h
// Needed to send an error on the ctrl connection
session->sockctrl_out = pars->sockctrl_out;
+ session->ctrl_ssl = pars->ssl;
session->protocol_version = pars->protocol_version;
// Now I can set the filter
- ret = daemon_unpackapplyfilter(pars->sockctrl_in, session, &plen, errmsgbuf);
+ ret = daemon_unpackapplyfilter(pars->sockctrl_in, pars->ssl, session, &plen, errmsgbuf);
if (ret == -1)
{
// Fatal error. A message has been logged; just give up.
@@ -1725,7 +1742,7 @@ daemon_msg_startcap_req(struct daemon_slpars *pars, uint32 plen, struct thread_h
startcapreply->portdata = htons(port);
}
- if (sock_send(pars->sockctrl_out, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
+ if (sock_send(pars->sockctrl_out, pars->ssl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
{
// That failed; log a message and give up.
rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
@@ -1754,6 +1771,22 @@ daemon_msg_startcap_req(struct daemon_slpars *pars, uint32 plen, struct thread_h
sockdata = socktemp;
}
+ SSL *ssl = NULL;
+ if (uses_ssl)
+ {
+#ifdef HAVE_OPENSSL
+ /* In both active or passive cases, wait for the client to initiate the
+ * TLS handshake. Yes during that time the control socket will not be
+ * served, but the same was true from the above call to accept(). */
+ ssl = ssl_promotion(1, sockdata, errbuf, PCAP_ERRBUF_SIZE);
+ if (! ssl)
+ {
+ rpcapd_log(LOGPRIO_ERROR, "TLS handshake failed: %s", errbuf);
+ goto error;
+ }
+#endif
+ }
+ session->data_ssl = ssl;
session->sockdata = sockdata;
// Now we have to create a new thread to receive packets
@@ -1784,7 +1817,7 @@ daemon_msg_startcap_req(struct daemon_slpars *pars, uint32 plen, struct thread_h
threaddata->have_thread = 1;
// Check if all the data has been read; if not, discard the data in excess
- if (rpcapd_discard(pars->sockctrl_in, plen) == -1)
+ if (rpcapd_discard(pars->sockctrl_in, pars->ssl, plen) == -1)
goto fatal_error;
*sessionp = session;
@@ -1822,10 +1855,16 @@ error:
{
if (session->fp)
pcap_close(session->fp);
+#ifdef HAVE_OPENSSL
+ if (session->ctrl_ssl)
+ SSL_free(session->ctrl_ssl);
+ if (session->data_ssl)
+ SSL_free(session->data_ssl);
+#endif
free(session);
}
- if (rpcap_senderror(pars->sockctrl_out, pars->protocol_version,
+ if (rpcap_senderror(pars->sockctrl_out, pars->ssl, pars->protocol_version,
PCAP_ERR_STARTCAPTURE, errmsgbuf, errbuf) == -1)
{
// That failed; log a message and give up.
@@ -1834,7 +1873,7 @@ error:
}
// Check if all the data has been read; if not, discard the data in excess
- if (rpcapd_discard(pars->sockctrl_in, plen) == -1)
+ if (rpcapd_discard(pars->sockctrl_in, pars->ssl, plen) == -1)
{
// Network error.
return -1;
@@ -1894,6 +1933,12 @@ fatal_error:
{
if (session->fp)
pcap_close(session->fp);
+#ifdef HAVE_OPENSSL
+ if (session->ctrl_ssl)
+ SSL_free(session->ctrl_ssl);
+ if (session->data_ssl)
+ SSL_free(session->data_ssl);
+#endif
free(session);
}
@@ -1940,18 +1985,13 @@ daemon_msg_endcap_req(struct daemon_slpars *pars, struct session *session, struc
#endif
threaddata->have_thread = 0;
}
- if (session->sockdata)
- {
- sock_close(session->sockdata, NULL, 0);
- session->sockdata = 0;
- }
- pcap_close(session->fp);
+ session_close(session);
rpcap_createhdr(&header, pars->protocol_version,
RPCAP_MSG_ENDCAP_REPLY, 0, 0);
- if (sock_send(pars->sockctrl_out, (char *) &header, sizeof(struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE) == -1)
+ if (sock_send(pars->sockctrl_out, pars->ssl, (char *) &header, sizeof(struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE) == -1)
{
// That failed; log a message and give up.
rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
@@ -1962,7 +2002,7 @@ daemon_msg_endcap_req(struct daemon_slpars *pars, struct session *session, struc
}
static int
-daemon_unpackapplyfilter(SOCKET sockctrl_in, struct session *session, uint32 *plenp, char *errmsgbuf)
+daemon_unpackapplyfilter(SOCKET sockctrl_in, SSL *ctrl_ssl, struct session *session, uint32 *plenp, char *errmsgbuf)
{
int status;
struct rpcap_filter filter;
@@ -1971,7 +2011,7 @@ daemon_unpackapplyfilter(SOCKET sockctrl_in, struct session *session, uint32 *pl
struct bpf_program bf_prog;
unsigned int i;
- status = rpcapd_recv(sockctrl_in, (char *) &filter,
+ status = rpcapd_recv(sockctrl_in, ctrl_ssl, (char *) &filter,
sizeof(struct rpcap_filter), plenp, errmsgbuf);
if (status == -1)
{
@@ -2002,7 +2042,7 @@ daemon_unpackapplyfilter(SOCKET sockctrl_in, struct session *session, uint32 *pl
for (i = 0; i < bf_prog.bf_len; i++)
{
- status = rpcapd_recv(sockctrl_in, (char *) &insn,
+ status = rpcapd_recv(sockctrl_in, ctrl_ssl, (char *) &insn,
sizeof(struct rpcap_filterbpf_insn), plenp, errmsgbuf);
if (status == -1)
{
@@ -2047,7 +2087,7 @@ daemon_msg_updatefilter_req(struct daemon_slpars *pars, struct session *session,
int ret; // status of daemon_unpackapplyfilter()
struct rpcap_header header; // keeps the answer to the updatefilter command
- ret = daemon_unpackapplyfilter(pars->sockctrl_in, session, &plen, errmsgbuf);
+ ret = daemon_unpackapplyfilter(pars->sockctrl_in, pars->ssl, session, &plen, errmsgbuf);
if (ret == -1)
{
// Fatal error. A message has been logged; just give up.
@@ -2060,7 +2100,7 @@ daemon_msg_updatefilter_req(struct daemon_slpars *pars, struct session *session,
}
// Check if all the data has been read; if not, discard the data in excess
- if (rpcapd_discard(pars->sockctrl_in, plen) == -1)
+ if (rpcapd_discard(pars->sockctrl_in, pars->ssl, plen) == -1)
{
// Network error.
return -1;
@@ -2070,7 +2110,7 @@ daemon_msg_updatefilter_req(struct daemon_slpars *pars, struct session *session,
rpcap_createhdr(&header, pars->protocol_version,
RPCAP_MSG_UPDATEFILTER_REPLY, 0, 0);
- if (sock_send(pars->sockctrl_out, (char *) &header, sizeof (struct rpcap_header), pcap_geterr(session->fp), PCAP_ERRBUF_SIZE))
+ if (sock_send(pars->sockctrl_out, pars->ssl, (char *) &header, sizeof (struct rpcap_header), pcap_geterr(session->fp), PCAP_ERRBUF_SIZE))
{
// That failed; log a messsage and give up.
rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
@@ -2080,11 +2120,11 @@ daemon_msg_updatefilter_req(struct daemon_slpars *pars, struct session *session,
return 0;
error:
- if (rpcapd_discard(pars->sockctrl_in, plen) == -1)
+ if (rpcapd_discard(pars->sockctrl_in, pars->ssl, plen) == -1)
{
return -1;
}
- rpcap_senderror(pars->sockctrl_out, pars->protocol_version,
+ rpcap_senderror(pars->sockctrl_out, pars->ssl, pars->protocol_version,
PCAP_ERR_UPDATEFILTER, errmsgbuf, NULL);
return 0;
@@ -2102,7 +2142,7 @@ daemon_msg_setsampling_req(struct daemon_slpars *pars, uint32 plen, struct rpcap
struct rpcap_sampling rpcap_samp;
int status;
- status = rpcapd_recv(pars->sockctrl_in, (char *) &rpcap_samp, sizeof(struct rpcap_sampling), &plen, errmsgbuf);
+ status = rpcapd_recv(pars->sockctrl_in, pars->ssl, (char *) &rpcap_samp, sizeof(struct rpcap_sampling), &plen, errmsgbuf);
if (status == -1)
{
return -1;
@@ -2120,14 +2160,14 @@ daemon_msg_setsampling_req(struct daemon_slpars *pars, uint32 plen, struct rpcap
rpcap_createhdr(&header, pars->protocol_version,
RPCAP_MSG_SETSAMPLING_REPLY, 0, 0);
- if (sock_send(pars->sockctrl_out, (char *) &header, sizeof (struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE) == -1)
+ if (sock_send(pars->sockctrl_out, pars->ssl, (char *) &header, sizeof (struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE) == -1)
{
// That failed; log a messsage and give up.
rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
return -1;
}
- if (rpcapd_discard(pars->sockctrl_in, plen) == -1)
+ if (rpcapd_discard(pars->sockctrl_in, pars->ssl, plen) == -1)
{
return -1;
}
@@ -2135,7 +2175,7 @@ daemon_msg_setsampling_req(struct daemon_slpars *pars, uint32 plen, struct rpcap
return 0;
error:
- if (rpcap_senderror(pars->sockctrl_out, pars->protocol_version,
+ if (rpcap_senderror(pars->sockctrl_out, pars->ssl, pars->protocol_version,
PCAP_ERR_AUTH, errmsgbuf, errbuf) == -1)
{
// That failed; log a message and give up.
@@ -2144,7 +2184,7 @@ error:
}
// Check if all the data has been read; if not, discard the data in excess
- if (rpcapd_discard(pars->sockctrl_in, plen) == -1)
+ if (rpcapd_discard(pars->sockctrl_in, pars->ssl, plen) == -1)
{
return -1;
}
@@ -2162,7 +2202,7 @@ daemon_msg_stats_req(struct daemon_slpars *pars, struct session *session, uint32
struct rpcap_stats *netstats; // statistics sent on the network
// Checks that the header does not contain other data; if so, discard it
- if (rpcapd_discard(pars->sockctrl_in, plen) == -1)
+ if (rpcapd_discard(pars->sockctrl_in, pars->ssl, plen) == -1)
{
// Network error.
return -1;
@@ -2206,7 +2246,7 @@ daemon_msg_stats_req(struct daemon_slpars *pars, struct session *session, uint32
}
// Send the packet
- if (sock_send(pars->sockctrl_out, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
+ if (sock_send(pars->sockctrl_out, pars->ssl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
{
rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
return -1;
@@ -2215,7 +2255,7 @@ daemon_msg_stats_req(struct daemon_slpars *pars, struct session *session, uint32
return 0;
error:
- rpcap_senderror(pars->sockctrl_out, pars->protocol_version,
+ rpcap_senderror(pars->sockctrl_out, pars->ssl, pars->protocol_version,
PCAP_ERR_GETSTATS, errmsgbuf, NULL);
return 0;
}
@@ -2376,7 +2416,7 @@ daemon_thrdatamain(void *ptr)
// Send the packet
// If the client dropped the connection, don't report an
// error, just quit.
- status = sock_send(session->sockdata, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE);
+ status = sock_send(session->sockdata, session->data_ssl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE);
if (status < 0)
{
if (status == -1)
@@ -2401,14 +2441,13 @@ daemon_thrdatamain(void *ptr)
if (retval == -1)
{
pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error reading the packets: %s", pcap_geterr(session->fp));
- rpcap_senderror(session->sockctrl_out, session->protocol_version,
+ rpcap_senderror(session->sockctrl_out, session->ctrl_ssl, session->protocol_version,
PCAP_ERR_READEX, errbuf, NULL);
goto error;
}
error:
- closesocket(session->sockdata);
- session->sockdata = 0;
+ session_close(session);
free(sendbuf);
@@ -2497,12 +2536,12 @@ void sleep_secs(int secs)
* Read the header of a message.
*/
static int
-rpcapd_recv_msg_header(SOCKET sock, struct rpcap_header *headerp)
+rpcapd_recv_msg_header(SOCKET sock, SSL *ssl, struct rpcap_header *headerp)
{
int nread;
char errbuf[PCAP_ERRBUF_SIZE]; // buffer for network errors
- nread = sock_recv(sock, (char *) headerp, sizeof(struct rpcap_header),
+ nread = sock_recv(sock, ssl, (char *) headerp, sizeof(struct rpcap_header),
SOCK_RECEIVEALL_YES|SOCK_EOF_ISNT_ERROR, errbuf, PCAP_ERRBUF_SIZE);
if (nread == -1)
{
@@ -2529,7 +2568,7 @@ rpcapd_recv_msg_header(SOCKET sock, struct rpcap_header *headerp)
* error.
*/
static int
-rpcapd_recv(SOCKET sock, char *buffer, size_t toread, uint32 *plen, char *errmsgbuf)
+rpcapd_recv(SOCKET sock, SSL *ssl, char *buffer, size_t toread, uint32 *plen, char *errmsgbuf)
{
int nread;
char errbuf[PCAP_ERRBUF_SIZE]; // buffer for network errors
@@ -2540,7 +2579,7 @@ rpcapd_recv(SOCKET sock, char *buffer, size_t toread, uint32 *plen, char *errmsg
pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Message payload is too short");
return -2;
}
- nread = sock_recv(sock, buffer, toread,
+ nread = sock_recv(sock, ssl, buffer, toread,
SOCK_RECEIVEALL_YES|SOCK_EOF_IS_ERROR, errbuf, PCAP_ERRBUF_SIZE);
if (nread == -1)
{
@@ -2558,13 +2597,13 @@ rpcapd_recv(SOCKET sock, char *buffer, size_t toread, uint32 *plen, char *errmsg
* error.
*/
static int
-rpcapd_discard(SOCKET sock, uint32 len)
+rpcapd_discard(SOCKET sock, SSL *ssl, uint32 len)
{
char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed
if (len != 0)
{
- if (sock_discard(sock, len, errbuf, PCAP_ERRBUF_SIZE) == -1)
+ if (sock_discard(sock, ssl, len, errbuf, PCAP_ERRBUF_SIZE) == -1)
{
// Network error.
rpcapd_log(LOGPRIO_ERROR, "Read from client failed: %s", errbuf);
@@ -2573,3 +2612,27 @@ rpcapd_discard(SOCKET sock, uint32 len)
}
return 0;
}
+
+/*
+ * Close the socket associated with the session, the optional SSL handle,
+ * and the underlying packet capture handle. We of course do not touch
+ * the controlling socket that's also copied into the session.
+ */
+static void session_close(struct session *session)
+{
+#ifdef HAVE_OPENSSL
+ if (session->data_ssl)
+ {
+ SSL_free(session->data_ssl); // Must happen *before* the socket is closed
+ session->data_ssl = NULL;
+ }
+#endif
+
+ if (session->sockdata)
+ {
+ sock_close(session->sockdata, NULL, 0);
+ session->sockdata = 0;
+ }
+
+ pcap_close(session->fp);
+}
diff --git a/rpcapd/daemon.h b/rpcapd/daemon.h
index bd240b80..83901e77 100644
--- a/rpcapd/daemon.h
+++ b/rpcapd/daemon.h
@@ -33,12 +33,18 @@
#ifndef __DAEMON_H__
#define __DAEMON_H__
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "sslutils.h"
+
//
// Returns 1 if the client closed the control connection explicitly, 0
// otherwise; used in active mode only.
//
-int daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive,
- int nullAuthAllowed);
+int daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, SSL *ssl,
+ int isactive, int nullAuthAllowed, int uses_ssl);
void sleep_secs(int secs);
diff --git a/rpcapd/rpcapd.c b/rpcapd/rpcapd.c
index 9e46a2de..0509147a 100644
--- a/rpcapd/rpcapd.c
+++ b/rpcapd/rpcapd.c
@@ -53,6 +53,10 @@
#include "daemon.h" // the true main() method of this daemon
#include "log.h"
+#ifdef HAVE_OPENSSL
+#include "sslutils.h"
+#endif
+
#ifdef _WIN32
#include <process.h> // for thread stuff
#include "win32-svc.h" // for Win32 service stuff
@@ -86,6 +90,7 @@ static HANDLE state_change_event; //!< event to signal that a state change shou
#endif
static volatile sig_atomic_t shutdown_server; //!< '1' if the server is to shut down
static volatile sig_atomic_t reread_config; //!< '1' if the server is to re-read its configuration
+static int uses_ssl; //!< '1' to use TLS over the data socket
extern char *optarg; // for getopt()
@@ -144,6 +149,12 @@ static void printusage(void)
#ifndef _WIN32
" -i run in inetd mode (UNIX only)\n\n"
#endif
+#ifdef HAVE_OPENSSL
+ " -S encrypt all communication with SSL (implements rpcaps://)\n"
+ " -C enable compression\n"
+ " -K <pem_file> uses the SSL private key in this file (default: key.pem)\n"
+ " -X <pem_file> uses the certificate from this file (default: cert.pem)\n"
+#endif
" -s <config_file> save the current configuration to file\n\n"
" -f <config_file> load the current configuration from file; all switches\n"
" specified from the command line are ignored\n\n"
@@ -169,6 +180,9 @@ int main(int argc, char *argv[])
#ifndef _WIN32
struct sigaction action;
#endif
+#ifdef HAVE_OPENSSL
+ int enable_compression = 0;
+#endif
savefile[0] = 0;
loadfile[0] = 0;
@@ -194,7 +208,15 @@ int main(int argc, char *argv[])
mainhints.ai_socktype = SOCK_STREAM;
// Getting the proper command line options
- while ((retval = getopt(argc, argv, "b:dhip:4l:na:s:f:v")) != -1)
+# ifdef HAVE_OPENSSL
+# define SSL_CLOPTS "SK:X:C"
+# else
+# define SSL_CLOPTS ""
+# endif
+
+# define CLOPTS "b:dhip:4l:na:s:f:v" SSL_CLOPTS
+
+ while ((retval = getopt(argc, argv, CLOPTS)) != -1)
{
switch (retval)
{
@@ -266,6 +288,20 @@ int main(int argc, char *argv[])
case 's':
pcap_strlcpy(savefile, optarg, MAX_LINE);
break;
+#ifdef HAVE_OPENSSL
+ case 'S':
+ uses_ssl = 1;
+ break;
+ case 'C':
+ enable_compression = 1;
+ break;
+ case 'K':
+ snprintf(ssl_keyfile, sizeof ssl_keyfile, "%s", optarg);
+ break;
+ case 'X':
+ snprintf(ssl_certfile, sizeof ssl_certfile, "%s", optarg);
+ break;
+#endif
case 'h':
printusage();
exit(0);
@@ -331,6 +367,10 @@ int main(int argc, char *argv[])
signal(SIGPIPE, SIG_IGN);
#endif
+# ifdef HAVE_OPENSSL
+ if (uses_ssl) init_ssl_or_die(1, enable_compression);
+# endif
+
#ifndef _WIN32
if (isrunbyinetd)
{
@@ -381,13 +421,26 @@ int main(int argc, char *argv[])
close(devnull_fd);
}
+ SSL *ssl = NULL;
+#ifdef HAVE_OPENSSL
+ if (uses_ssl)
+ {
+ ssl = ssl_promotion_rw(1, sockctrl_in, sockctrl_out, errbuf, PCAP_ERRBUF_SIZE);
+ if (! ssl)
+ {
+ rpcapd_log(LOGPRIO_ERROR, "TLS handshake on control connection failed: %s",
+ errbuf);
+ exit(2);
+ }
+ }
+#endif
//
// Handle this client.
// This is passive mode, so we don't care whether we were
// told by the client to close.
//
- (void)daemon_serviceloop(sockctrl_in, sockctrl_out, 0,
- nullAuthAllowed);
+ (void)daemon_serviceloop(sockctrl_in, sockctrl_out, ssl, 0,
+ nullAuthAllowed, uses_ssl);
//
// Nothing more to do.
@@ -1033,6 +1086,22 @@ accept_connections(void)
sock_cleanup();
}
+#ifdef _WIN32
+//
+// A structure to hold the parameter to the windows thread
+// (on unix there is no need for this explicit copy since the
+// fork "inherits" the parent stack)
+//
+struct sock_copy {
+ SOCKET sockctrl;
+# ifdef HAVE_OPENSSL
+ SSL *ssl;
+# else
+ void *ssl;
+# endif
+};
+#endif
+
//
// Accept a connection and start a worker thread, on Windows, or a
// worker process, on UN*X, to handle the connection.
@@ -1045,10 +1114,12 @@ accept_connection(SOCKET listen_sock)
struct sockaddr_storage from; // generic sockaddr_storage variable
socklen_t fromlen; // keeps the length of the sockaddr_storage variable
+ SSL *ssl = NULL;
+
#ifdef _WIN32
HANDLE threadId; // handle for the subthread
u_long off = 0;
- SOCKET *sockctrl_temp;
+ struct sock_copy *sock_copy = NULL;
#else
pid_t pid;
#endif
@@ -1087,15 +1158,29 @@ accept_connection(SOCKET listen_sock)
return;
}
+#ifdef HAVE_OPENSSL
+ /* We have to upgrade to TLS as soon as possible so that the whole protocol
+ * goes through the encrypted tunnel, including early error messages. */
+ if (uses_ssl)
+ {
+ ssl = ssl_promotion(1, sockctrl, errbuf, PCAP_ERRBUF_SIZE);
+ if (! ssl)
+ {
+ rpcapd_log(LOGPRIO_ERROR, "TLS handshake on control connection failed: %s",
+ errbuf);
+ goto error;
+ }
+ }
+#endif
+
//
// We have a connection.
// Check whether 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, 0, PCAP_ERR_HOSTNOAUTH, errbuf, NULL);
- sock_close(sockctrl, NULL, 0);
- return;
+ rpcap_senderror(sockctrl, ssl, 0, PCAP_ERR_HOSTNOAUTH, errbuf, NULL);
+ goto error;
}
#ifdef _WIN32
@@ -1111,16 +1196,14 @@ accept_connection(SOCKET listen_sock)
if (WSAEventSelect(sockctrl, NULL, 0) == SOCKET_ERROR)
{
sock_geterror("ioctlsocket(FIONBIO): ", errbuf, PCAP_ERRBUF_SIZE);
- rpcap_senderror(sockctrl, 0, PCAP_ERR_HOSTNOAUTH, errbuf, NULL);
- sock_close(sockctrl, NULL, 0);
- return;
+ rpcap_senderror(sockctrl, ssl, 0, PCAP_ERR_HOSTNOAUTH, errbuf, NULL);
+ goto error;
}
if (ioctlsocket(sockctrl, FIONBIO, &off) == SOCKET_ERROR)
{
sock_geterror("ioctlsocket(FIONBIO): ", errbuf, PCAP_ERRBUF_SIZE);
- rpcap_senderror(sockctrl, 0, PCAP_ERR_HOSTNOAUTH, errbuf, NULL);
- sock_close(sockctrl, NULL, 0);
- return;
+ rpcap_senderror(sockctrl, ssl, 0, PCAP_ERR_HOSTNOAUTH, errbuf, NULL);
+ goto error;
}
//
@@ -1130,26 +1213,24 @@ accept_connection(SOCKET listen_sock)
// I guess we *could* just cast sockctrl to a void *, but that's
// a bit ugly.
//
- sockctrl_temp = (SOCKET *)malloc(sizeof (SOCKET));
- if (sockctrl_temp == NULL)
+ sock_copy = malloc(sizeof(*sock_copy));
+ if (sock_copy == NULL)
{
pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
errno, "malloc() failed");
- rpcap_senderror(sockctrl, 0, PCAP_ERR_OPEN, errbuf, NULL);
- sock_close(sockctrl, NULL, 0);
- return;
+ rpcap_senderror(sockctrl, ssl, 0, PCAP_ERR_OPEN, errbuf, NULL);
+ goto error;
}
- *sockctrl_temp = sockctrl;
+ sock_copy->sockctrl = sockctrl;
+ sock_copy->ssl = NULL;
threadId = (HANDLE)_beginthreadex(NULL, 0,
- main_passive_serviceloop_thread, (void *) sockctrl_temp, 0, NULL);
+ main_passive_serviceloop_thread, (void *) sock_copy, 0, NULL);
if (threadId == 0)
{
pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error creating the child thread");
- rpcap_senderror(sockctrl, 0, PCAP_ERR_OPEN, errbuf, NULL);
- sock_close(sockctrl, NULL, 0);
- free(sockctrl_temp);
- return;
+ rpcap_senderror(sockctrl, ssl, 0, PCAP_ERR_OPEN, errbuf, NULL);
+ goto error;
}
CloseHandle(threadId);
#else
@@ -1157,9 +1238,8 @@ accept_connection(SOCKET listen_sock)
if (pid == -1)
{
pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error creating the child process");
- rpcap_senderror(sockctrl, 0, PCAP_ERR_OPEN, errbuf, NULL);
- sock_close(sockctrl, NULL, 0);
- return;
+ rpcap_senderror(sockctrl, ssl, 0, PCAP_ERR_OPEN, errbuf, NULL);
+ goto error;
}
if (pid == 0)
{
@@ -1190,8 +1270,8 @@ accept_connection(SOCKET listen_sock)
// This is passive mode, so we don't care whether we were
// told by the client to close.
//
- (void)daemon_serviceloop(sockctrl, sockctrl, 0,
- nullAuthAllowed);
+ (void)daemon_serviceloop(sockctrl, sockctrl, ssl, 0,
+ nullAuthAllowed, uses_ssl);
close(sockctrl);
@@ -1200,8 +1280,25 @@ accept_connection(SOCKET listen_sock)
// I am the parent
// Close the socket for this session (must be open only in the child)
+#ifdef HAVE_OPENSSL
+ if (ssl)
+ {
+ SSL_free(ssl);
+ ssl = NULL;
+ }
+#endif
closesocket(sockctrl);
#endif
+ return;
+
+error:
+#ifdef _WIN32
+ if (sock_copy) free(sock_copy);
+#endif
+#ifdef HAVE_OPENSSL
+ if (ssl) SSL_free(ssl); // Have to be done before closing soskctrl
+#endif
+ sock_close(sockctrl, NULL, 0);
}
/*!
@@ -1225,6 +1322,7 @@ main_active(void *ptr)
struct addrinfo hints; // temporary struct to keep settings needed to open the new socket
struct addrinfo *addrinfo; // keeps the addrinfo chain; required to open a new socket
struct active_pars *activepars;
+ SSL *ssl = NULL;
activepars = (struct active_pars *) ptr;
@@ -1269,9 +1367,28 @@ main_active(void *ptr)
continue;
}
- activeclose = daemon_serviceloop(sockctrl, sockctrl, 1,
- nullAuthAllowed);
+#ifdef HAVE_OPENSSL
+ /* Even in active mode the other other end has to initiate the TLS handshake
+ * as we still are the server as far as TLS is concerned: */
+ if (uses_ssl)
+ {
+ ssl = ssl_promotion(1, sockctrl, errbuf, PCAP_ERRBUF_SIZE);
+ if (! ssl)
+ {
+ rpcapd_log(LOGPRIO_ERROR, "TLS handshake on control connection failed: %s",
+ errbuf);
+ sock_close(sockctrl, NULL, 0);
+ continue;
+ }
+ }
+#endif
+
+ activeclose = daemon_serviceloop(sockctrl, sockctrl, ssl, 1,
+ nullAuthAllowed, uses_ssl);
+#ifdef HAVE_OPENSSL
+ if (ssl) SSL_free(ssl);
+#endif
sock_close(sockctrl, NULL, 0);
// If the connection is closed by the user explicitely, don't try to connect to it again
@@ -1290,9 +1407,7 @@ main_active(void *ptr)
//
unsigned __stdcall main_passive_serviceloop_thread(void *ptr)
{
- SOCKET sockctrl;
-
- sockctrl = *((SOCKET *)ptr);
+ struct sock_copy sock = *(struct sock_copy *)ptr;
free(ptr);
//
@@ -1300,9 +1415,10 @@ unsigned __stdcall main_passive_serviceloop_thread(void *ptr)
// This is passive mode, so we don't care whether we were
// told by the client to close.
//
- (void)daemon_serviceloop(sockctrl, sockctrl, 0, nullAuthAllowed);
+ (void)daemon_serviceloop(sock.sockctrl, sock.sockctrl, sock.ssl, 0,
+ nullAuthAllowed, uses_ssl);
- sock_close(sockctrl, NULL, 0);
+ sock_close(sock.sockctrl, NULL, 0);
return 0;
}
diff --git a/sockutils.c b/sockutils.c
index 7ed7d298..25844c6c 100644
--- a/sockutils.c
+++ b/sockutils.c
@@ -640,7 +640,7 @@ int sock_initaddress(const char *host, const char *port,
* '-2' if we got one of those errors.
* For errors, an error message is returned in the 'errbuf' variable.
*/
-int sock_send(SOCKET sock, const char *buffer, size_t size,
+int sock_send(SOCKET sock, SSL *ssl, const char *buffer, size_t size,
char *errbuf, int errbuflen)
{
int remaining;
@@ -659,6 +659,12 @@ int sock_send(SOCKET sock, const char *buffer, size_t size,
remaining = (int)size;
do {
+#ifdef HAVE_OPENSSL
+ if (ssl) return ssl_send(ssl, buffer, remaining, errbuf, errbuflen);
+#else
+ (void)ssl;
+#endif
+
#ifdef MSG_NOSIGNAL
/*
* Send with MSG_NOSIGNAL, so that we don't get SIGPIPE
@@ -835,7 +841,7 @@ int sock_bufferize(const char *buffer, int size, char *tempbuf, int *offset, int
* The error message is returned in the 'errbuf' variable.
*/
-int sock_recv(SOCKET sock, void *buffer, size_t size, int flags,
+int sock_recv(SOCKET sock, SSL *ssl, void *buffer, size_t size, int flags,
char *errbuf, int errbuflen)
{
int recv_flags = 0;
@@ -870,7 +876,20 @@ int sock_recv(SOCKET sock, void *buffer, size_t size, int flags,
* Win32.
*/
for (;;) {
+#ifdef HAVE_OPENSSL
+ if (ssl)
+ {
+ /*
+ * XXX - what about MSG_PEEK?
+ */
+ nread = ssl_recv(ssl, bufp, remaining, errbuf, errbuflen);
+ if (nread == -2) return -1;
+ }
+ else
+ nread = recv(sock, bufp, remaining, recv_flags);
+#else
nread = recv(sock, bufp, remaining, recv_flags);
+#endif
if (nread == -1)
{
@@ -928,7 +947,7 @@ int sock_recv(SOCKET sock, void *buffer, size_t size, int flags,
*
* Returns the size of the datagram on success or -1 on error.
*/
-int sock_recv_dgram(SOCKET sock, void *buffer, size_t size,
+int sock_recv_dgram(SOCKET sock, SSL *ssl, void *buffer, size_t size,
char *errbuf, int errbuflen)
{
ssize_t nread;
@@ -953,6 +972,13 @@ int sock_recv_dgram(SOCKET sock, void *buffer, size_t size,
return -1;
}
+ // TODO: DTLS
+ if (ssl)
+ {
+ pcap_snprintf(errbuf, errbuflen, "DTLS not implemented yet");
+ return -1;
+ }
+
/*
* This should be a datagram socket, so we should get the
* entire datagram in one recv() or recvmsg() call, and
@@ -1063,7 +1089,7 @@ int sock_recv_dgram(SOCKET sock, void *buffer, size_t size,
* \return '0' if everything is fine, '-1' if some errors occurred.
* The error message is returned in the 'errbuf' variable.
*/
-int sock_discard(SOCKET sock, int size, char *errbuf, int errbuflen)
+int sock_discard(SOCKET sock, SSL *ssl, int size, char *errbuf, int errbuflen)
{
#define TEMP_BUF_SIZE 32768
@@ -1079,7 +1105,7 @@ int sock_discard(SOCKET sock, int size, char *errbuf, int errbuflen)
*/
while (size > TEMP_BUF_SIZE)
{
- if (sock_recv(sock, buffer, TEMP_BUF_SIZE, SOCK_RECEIVEALL_YES, errbuf, errbuflen) == -1)
+ if (sock_recv(sock, ssl, buffer, TEMP_BUF_SIZE, SOCK_RECEIVEALL_YES, errbuf, errbuflen) == -1)
return -1;
size -= TEMP_BUF_SIZE;
@@ -1091,7 +1117,7 @@ int sock_discard(SOCKET sock, int size, char *errbuf, int errbuflen)
*/
if (size)
{
- if (sock_recv(sock, buffer, size, SOCK_RECEIVEALL_YES, errbuf, errbuflen) == -1)
+ if (sock_recv(sock, ssl, buffer, size, SOCK_RECEIVEALL_YES, errbuf, errbuflen) == -1)
return -1;
}
diff --git a/sockutils.h b/sockutils.h
index 3102fcef..fc271bf9 100644
--- a/sockutils.h
+++ b/sockutils.h
@@ -101,6 +101,8 @@
#define closesocket(a) close(a)
#endif
+#include "sslutils.h" // for SSL type, whatever that turns out to be
+
/*
* MingW headers include this definition, but only for Windows XP and above.
* MSDN states that this function is available for most versions on Windows.
@@ -208,17 +210,17 @@ void sock_geterror(const char *caller, char *errbuf, int errbufsize);
int sock_initaddress(const char *address, const char *port,
struct addrinfo *hints, struct addrinfo **addrinfo,
char *errbuf, int errbuflen);
-int sock_recv(SOCKET sock, void *buffer, size_t size, int receiveall,
+int sock_recv(SOCKET sock, SSL *, void *buffer, size_t size, int receiveall,
char *errbuf, int errbuflen);
-int sock_recv_dgram(SOCKET sock, void *buffer, size_t size,
+int sock_recv_dgram(SOCKET sock, SSL *, void *buffer, size_t size,
char *errbuf, int errbuflen);
SOCKET sock_open(struct addrinfo *addrinfo, int server, int nconn, char *errbuf, int errbuflen);
int sock_close(SOCKET sock, char *errbuf, int errbuflen);
-int sock_send(SOCKET sock, const char *buffer, size_t size,
+int sock_send(SOCKET sock, SSL *, const char *buffer, size_t size,
char *errbuf, int errbuflen);
int sock_bufferize(const char *buffer, int size, char *tempbuf, int *offset, int totsize, int checkonly, char *errbuf, int errbuflen);
-int sock_discard(SOCKET sock, int size, char *errbuf, int errbuflen);
+int sock_discard(SOCKET sock, SSL *, int size, char *errbuf, int errbuflen);
int sock_check_hostlist(char *hostlist, const char *sep, struct sockaddr_storage *from, char *errbuf, int errbuflen);
int sock_cmpaddr(struct sockaddr_storage *first, struct sockaddr_storage *second);
diff --git a/sslutils.c b/sslutils.c
new file mode 100644
index 00000000..c6fb80c5
--- /dev/null
+++ b/sslutils.c
@@ -0,0 +1,227 @@
+/*
+ * 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
+
+#ifdef HAVE_OPENSSL
+#include <stdlib.h>
+
+#include "portability.h"
+#include "sslutils.h"
+#include "pcap/pcap.h"
+
+char ssl_keyfile[PATH_MAX]; //!< file containing the private key in PEM format
+char ssl_certfile[PATH_MAX]; //!< file containing the server's certificate in PEM format
+char ssl_rootfile[PATH_MAX]; //!< file containing the list of CAs trusted by the client
+// TODO: a way to set ssl_rootfile from the command line, or an envvar?
+
+// TODO: lock?
+static SSL_CTX *ctx;
+
+static int ssl_init_once(int is_server, int enable_compression, char *errbuf, size_t errbuflen)
+{
+ static int inited = 0;
+ if (inited) return 0;
+
+ SSL_library_init();
+ SSL_load_error_strings();
+ OpenSSL_add_ssl_algorithms();
+ if (enable_compression)
+ SSL_COMP_get_compression_methods();
+
+ SSL_METHOD const *meth =
+ is_server ? SSLv23_server_method() : SSLv23_client_method();
+ ctx = SSL_CTX_new(meth);
+ if (! ctx)
+ {
+ pcap_snprintf(errbuf, errbuflen, "Cannot get a new SSL context: %s", ERR_error_string(ERR_get_error(), NULL));
+ goto die;
+ }
+
+ SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
+
+ if (is_server)
+ {
+ char const *certfile = ssl_certfile[0] ? ssl_certfile : "cert.pem";
+ if (1 != SSL_CTX_use_certificate_file(ctx, certfile, SSL_FILETYPE_PEM))
+ {
+ pcap_snprintf(errbuf, errbuflen, "Cannot read certificate file %s: %s", certfile, ERR_error_string(ERR_get_error(), NULL));
+ goto die;
+ }
+
+ char const *keyfile = ssl_keyfile[0] ? ssl_keyfile : "key.pem";
+ if (1 != SSL_CTX_use_PrivateKey_file(ctx, keyfile, SSL_FILETYPE_PEM))
+ {
+ pcap_snprintf(errbuf, errbuflen, "Cannot read private key file %s: %s", keyfile, ERR_error_string(ERR_get_error(), NULL));
+ goto die;
+ }
+ }
+ else
+ {
+ if (ssl_rootfile[0])
+ {
+ if (! SSL_CTX_load_verify_locations(ctx, ssl_rootfile, 0))
+ {
+ pcap_snprintf(errbuf, errbuflen, "Cannot read CA list from %s", ssl_rootfile);
+ goto die;
+ }
+ }
+ else
+ {
+ SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
+ }
+ }
+
+#if 0
+ if (! RAND_load_file(RANDOM, 1024*1024))
+ {
+ pcap_snprintf(errbuf, errbuflen, "Cannot init random");
+ goto die;
+ }
+
+ if (is_server)
+ {
+ SSL_CTX_set_session_id_context(ctx, (void *)&s_server_session_id_context, sizeof(s_server_session_id_context));
+ }
+#endif
+
+ inited = 1;
+ return 0;
+
+die:
+ return -1;
+}
+
+void init_ssl_or_die(int is_server, int enable_compression)
+{
+ char errbuf[PCAP_ERRBUF_SIZE];
+
+ if (ssl_init_once(is_server, enable_compression, errbuf, sizeof errbuf) < 0)
+ {
+ fprintf(stderr, "%s\n", errbuf);
+ exit(3);
+ }
+}
+
+SSL *ssl_promotion_rw(int is_server, SOCKET in, SOCKET out, char *errbuf, size_t errbuflen)
+{
+ if (ssl_init_once(is_server, 1, errbuf, errbuflen) < 0) {
+ return NULL;
+ }
+
+ SSL *ssl = SSL_new(ctx); // TODO: also a DTLS context
+ SSL_set_rfd(ssl, in);
+ SSL_set_wfd(ssl, out);
+
+ if (is_server) {
+ if (SSL_accept(ssl) <= 0) {
+ pcap_snprintf(errbuf, errbuflen, "SSL_accept(): %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ return NULL;
+ }
+ } else {
+ if (SSL_connect(ssl) <= 0) {
+ pcap_snprintf(errbuf, errbuflen, "SSL_connect(): %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ return NULL;
+ }
+ }
+
+ return ssl;
+}
+
+SSL *ssl_promotion(int is_server, SOCKET s, char *errbuf, size_t errbuflen)
+{
+ return ssl_promotion_rw(is_server, s, s, errbuf, errbuflen);
+}
+
+// Same return value as sock_send:
+// 0 on OK, -1 on error but closed connection (-2).
+int ssl_send(SSL *ssl, char const *buffer, size_t size, char *errbuf, size_t errbuflen)
+{
+ int status = SSL_write(ssl, buffer, size);
+ if (status > 0)
+ {
+ // "SSL_write() will only return with success, when the complete contents (...) has been written."
+ return 0;
+ }
+ else
+ {
+ int ssl_err = SSL_get_error(ssl, status); // TODO: does it pop the error?
+ if (ssl_err == SSL_ERROR_ZERO_RETURN)
+ {
+ return -2;
+ }
+ else if (ssl_err == SSL_ERROR_SYSCALL)
+ {
+#ifndef _WIN32
+ if (errno == ECONNRESET || errno == EPIPE) return -2;
+#endif
+ }
+ pcap_snprintf(errbuf, errbuflen, "SSL_write(): %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ return -1;
+ }
+}
+
+// Returns the number of bytes read, or -1 on syserror, or -2 on SSL error.
+int ssl_recv(SSL *ssl, char *buffer, size_t size, char *errbuf, size_t errbuflen)
+{
+ int status = SSL_read(ssl, buffer, size);
+ if (status <= 0)
+ {
+ int ssl_err = SSL_get_error(ssl, status);
+ if (ssl_err == SSL_ERROR_ZERO_RETURN)
+ {
+ return 0;
+ }
+ else if (ssl_err == SSL_ERROR_SYSCALL)
+ {
+ return -1;
+ }
+ else
+ {
+ // Should not happen
+ pcap_snprintf(errbuf, errbuflen, "SSL_read(): %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ return -2;
+ }
+ }
+ else
+ {
+ return status;
+ }
+}
+
+#endif // HAVE_OPENSSL
diff --git a/sslutils.h b/sslutils.h
new file mode 100644
index 00000000..41a243e3
--- /dev/null
+++ b/sslutils.h
@@ -0,0 +1,70 @@
+/*
+ * 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 __SSLUTILS_H__
+#define __SSLUTILS_H__
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_OPENSSL
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include "pcap/pcap.h" // for SOCKET
+
+/*
+ * Configuration parameters
+ */
+
+extern char ssl_keyfile[PATH_MAX];
+extern char ssl_certfile[PATH_MAX];
+extern char ssl_rootfile[PATH_MAX];
+
+/*
+ * Utility functions
+ */
+
+void init_ssl_or_die(int is_server, int enable_compression);
+SSL *ssl_promotion(int is_server, SOCKET s, char *errbuf, size_t errbuflen);
+SSL *ssl_promotion_rw(int is_server, SOCKET in, SOCKET out, char *errbuf, size_t errbuflen);
+int ssl_send(SSL *, char const *buffer, size_t size, char *errbuf, size_t errbuflen);
+int ssl_recv(SSL *, char *buffer, size_t size, char *errbuf, size_t errbuflen);
+
+#else // HAVE_OPENSSL
+
+// This saves us from a lot of ifdefs:
+#define SSL void const
+
+#endif // HAVE_OPENSSL
+
+#endif // __SSLUTILS_H__