1
1
Add an optional mode that requires clients to authenticate with the server.

In this mode, clients need to provide a username and a password, which are checked against a password file on the server.  The authentication credentials are protected by an RSA public keypair...the encrypted credentials are sent along with the test parameters.

Operationally the use of this feature places the following additional requirements on the build and installation of iperf3:

o The presence of the OpenSSL headers and libraries to build iperf3, and the libraries available on the client and server at runtime.

o Generation of an RSA public keypair; the private part is used by the server and the public part must be distributed to the clients.

o Username/password pairs for all authorized users, to be stored in a file on the server.

o Loose time synchronization between the server and clients (to within approximately 30 seconds).

o Appropriate command-line flags given on the client and server.

Note that iperf3 can be built and run as before, without fulfilling any of these requirements.

Partial documentation for this feature is included in this commit.  It is anticipated that additional documentation text and editing will follow this merge.

Submitted by @ralcini.  First suggested by @codyhanson in pull request #242.
Этот коммит содержится в:
ralcini 2017-04-20 19:01:08 +02:00 коммит произвёл Bruce A. Mah
родитель 05600c201a
Коммит a51045de19
16 изменённых файлов: 1064 добавлений и 32 удалений

124
ax_check_openssl.m4 Обычный файл
Просмотреть файл

@ -0,0 +1,124 @@
# ===========================================================================
# https://www.gnu.org/software/autoconf-archive/ax_check_openssl.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_CHECK_OPENSSL([action-if-found[, action-if-not-found]])
#
# DESCRIPTION
#
# Look for OpenSSL in a number of default spots, or in a user-selected
# spot (via --with-openssl). Sets
#
# OPENSSL_INCLUDES to the include directives required
# OPENSSL_LIBS to the -l directives required
# OPENSSL_LDFLAGS to the -L or -R flags required
#
# and calls ACTION-IF-FOUND or ACTION-IF-NOT-FOUND appropriately
#
# This macro sets OPENSSL_INCLUDES such that source files should use the
# openssl/ directory in include directives:
#
# #include <openssl/hmac.h>
#
# LICENSE
#
# Copyright (c) 2009,2010 Zmanda Inc. <http://www.zmanda.com/>
# Copyright (c) 2009,2010 Dustin J. Mitchell <dustin@zmanda.com>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 10
AU_ALIAS([CHECK_SSL], [AX_CHECK_OPENSSL])
AC_DEFUN([AX_CHECK_OPENSSL], [
found=false
AC_ARG_WITH([openssl],
[AS_HELP_STRING([--with-openssl=DIR],
[root of the OpenSSL directory])],
[
case "$withval" in
"" | y | ye | yes | n | no)
AC_MSG_ERROR([Invalid --with-openssl value])
;;
*) ssldirs="$withval"
;;
esac
], [
# if pkg-config is installed and openssl has installed a .pc file,
# then use that information and don't search ssldirs
AC_CHECK_TOOL([PKG_CONFIG], [pkg-config])
if test x"$PKG_CONFIG" != x""; then
OPENSSL_LDFLAGS=`$PKG_CONFIG openssl --libs-only-L 2>/dev/null`
if test $? = 0; then
OPENSSL_LIBS=`$PKG_CONFIG openssl --libs-only-l 2>/dev/null`
OPENSSL_INCLUDES=`$PKG_CONFIG openssl --cflags-only-I 2>/dev/null`
found=true
fi
fi
# no such luck; use some default ssldirs
if ! $found; then
ssldirs="/usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /usr"
fi
]
)
# note that we #include <openssl/foo.h>, so the OpenSSL headers have to be in
# an 'openssl' subdirectory
if ! $found; then
OPENSSL_INCLUDES=
for ssldir in $ssldirs; do
AC_MSG_CHECKING([for openssl/ssl.h in $ssldir])
if test -f "$ssldir/include/openssl/ssl.h"; then
OPENSSL_INCLUDES="-I$ssldir/include"
OPENSSL_LDFLAGS="-L$ssldir/lib"
OPENSSL_LIBS="-lssl -lcrypto"
found=true
AC_MSG_RESULT([yes])
break
else
AC_MSG_RESULT([no])
fi
done
# if the file wasn't found, well, go ahead and try the link anyway -- maybe
# it will just work!
fi
# try the preprocessor and linker with our new flags,
# being careful not to pollute the global LIBS, LDFLAGS, and CPPFLAGS
AC_MSG_CHECKING([whether compiling and linking against OpenSSL works])
echo "Trying link with OPENSSL_LDFLAGS=$OPENSSL_LDFLAGS;" \
"OPENSSL_LIBS=$OPENSSL_LIBS; OPENSSL_INCLUDES=$OPENSSL_INCLUDES" >&AS_MESSAGE_LOG_FD
save_LIBS="$LIBS"
save_LDFLAGS="$LDFLAGS"
save_CPPFLAGS="$CPPFLAGS"
LDFLAGS="$LDFLAGS $OPENSSL_LDFLAGS"
LIBS="$OPENSSL_LIBS $LIBS"
CPPFLAGS="$OPENSSL_INCLUDES $CPPFLAGS"
AC_LINK_IFELSE(
[AC_LANG_PROGRAM([#include <openssl/ssl.h>], [SSL_new(NULL)])],
[
AC_MSG_RESULT([yes])
$1
], [
AC_MSG_RESULT([no])
$2
])
CPPFLAGS="$save_CPPFLAGS"
LDFLAGS="$save_LDFLAGS"
LIBS="$save_LIBS"
AC_SUBST([OPENSSL_INCLUDES])
AC_SUBST([OPENSSL_LIBS])
AC_SUBST([OPENSSL_LDFLAGS])
])

274
configure поставляемый
Просмотреть файл

@ -635,6 +635,10 @@ ac_subst_vars='am__EXEEXT_FALSE
am__EXEEXT_TRUE
LTLIBOBJS
LIBOBJS
OPENSSL_LDFLAGS
OPENSSL_LIBS
OPENSSL_INCLUDES
PKG_CONFIG
CPP
LT_SYS_LIBRARY_PATH
OTOOL64
@ -765,6 +769,7 @@ with_aix_soname
with_gnu_ld
with_sysroot
enable_libtool_lock
with_openssl
'
ac_precious_vars='build_alias
host_alias
@ -1420,6 +1425,7 @@ Optional Packages:
--with-gnu-ld assume the C compiler uses GNU ld [default=no]
--with-sysroot[=DIR] Search for dependent libraries within DIR (or the
compiler's sysroot if not specified).
--with-openssl=DIR root of the OpenSSL directory
Some influential environment variables:
CC C compiler command
@ -2217,6 +2223,63 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $
ac_compiler_gnu=$ac_cv_c_compiler_gnu
# ===========================================================================
# https://www.gnu.org/software/autoconf-archive/ax_check_openssl.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_CHECK_OPENSSL([action-if-found[, action-if-not-found]])
#
# DESCRIPTION
#
# Look for OpenSSL in a number of default spots, or in a user-selected
# spot (via --with-openssl). Sets
#
# OPENSSL_INCLUDES to the include directives required
# OPENSSL_LIBS to the -l directives required
# OPENSSL_LDFLAGS to the -L or -R flags required
#
# and calls ACTION-IF-FOUND or ACTION-IF-NOT-FOUND appropriately
#
# This macro sets OPENSSL_INCLUDES such that source files should use the
# openssl/ directory in include directives:
#
# #include <openssl/hmac.h>
#
# LICENSE
#
# Copyright (c) 2009,2010 Zmanda Inc. <http://www.zmanda.com/>
# Copyright (c) 2009,2010 Dustin J. Mitchell <dustin@zmanda.com>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 10
# This is what autoupdate's m4 run will expand. It fires
# the warning (with _au_warn_XXX), outputs it into the
# updated configure.ac (with AC_DIAGNOSE), and then outputs
# the replacement expansion.
# This is an auxiliary macro that is also run when
# autoupdate runs m4. It simply calls m4_warning, but
# we need a wrapper so that each warning is emitted only
# once. We break the quoting in m4_warning's argument in
# order to expand this macro's arguments, not AU_DEFUN's.
# Finally, this is the expansion that is picked up by
# autoconf. It tells the user to run autoupdate, and
# then outputs the replacement expansion. We do not care
# about autoupdate's warning because that contains
# information on what to do *after* running autoupdate.
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
@ -12673,6 +12736,217 @@ fi
done
# Check for OPENSSL support
found=false
# Check whether --with-openssl was given.
if test "${with_openssl+set}" = set; then :
withval=$with_openssl;
case "$withval" in
"" | y | ye | yes | n | no)
as_fn_error $? "Invalid --with-openssl value" "$LINENO" 5
;;
*) ssldirs="$withval"
;;
esac
else
# if pkg-config is installed and openssl has installed a .pc file,
# then use that information and don't search ssldirs
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_prog_PKG_CONFIG+:} false; then :
$as_echo_n "(cached) " >&6
else
if test -n "$PKG_CONFIG"; then
ac_cv_prog_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test.
else
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_prog_PKG_CONFIG="${ac_tool_prefix}pkg-config"
$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
fi
fi
PKG_CONFIG=$ac_cv_prog_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_prog_PKG_CONFIG"; then
ac_ct_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_prog_ac_ct_PKG_CONFIG+:} false; then :
$as_echo_n "(cached) " >&6
else
if test -n "$ac_ct_PKG_CONFIG"; then
ac_cv_prog_ac_ct_PKG_CONFIG="$ac_ct_PKG_CONFIG" # Let the user override the test.
else
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_prog_ac_ct_PKG_CONFIG="pkg-config"
$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
fi
fi
ac_ct_PKG_CONFIG=$ac_cv_prog_ac_ct_PKG_CONFIG
if test -n "$ac_ct_PKG_CONFIG"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_PKG_CONFIG" >&5
$as_echo "$ac_ct_PKG_CONFIG" >&6; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
if test "x$ac_ct_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_ct_PKG_CONFIG
fi
else
PKG_CONFIG="$ac_cv_prog_PKG_CONFIG"
fi
if test x"$PKG_CONFIG" != x""; then
OPENSSL_LDFLAGS=`$PKG_CONFIG openssl --libs-only-L 2>/dev/null`
if test $? = 0; then
OPENSSL_LIBS=`$PKG_CONFIG openssl --libs-only-l 2>/dev/null`
OPENSSL_INCLUDES=`$PKG_CONFIG openssl --cflags-only-I 2>/dev/null`
found=true
fi
fi
# no such luck; use some default ssldirs
if ! $found; then
ssldirs="/usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /usr"
fi
fi
# note that we #include <openssl/foo.h>, so the OpenSSL headers have to be in
# an 'openssl' subdirectory
if ! $found; then
OPENSSL_INCLUDES=
for ssldir in $ssldirs; do
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for openssl/ssl.h in $ssldir" >&5
$as_echo_n "checking for openssl/ssl.h in $ssldir... " >&6; }
if test -f "$ssldir/include/openssl/ssl.h"; then
OPENSSL_INCLUDES="-I$ssldir/include"
OPENSSL_LDFLAGS="-L$ssldir/lib"
OPENSSL_LIBS="-lssl -lcrypto"
found=true
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
break
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
done
# if the file wasn't found, well, go ahead and try the link anyway -- maybe
# it will just work!
fi
# try the preprocessor and linker with our new flags,
# being careful not to pollute the global LIBS, LDFLAGS, and CPPFLAGS
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiling and linking against OpenSSL works" >&5
$as_echo_n "checking whether compiling and linking against OpenSSL works... " >&6; }
echo "Trying link with OPENSSL_LDFLAGS=$OPENSSL_LDFLAGS;" \
"OPENSSL_LIBS=$OPENSSL_LIBS; OPENSSL_INCLUDES=$OPENSSL_INCLUDES" >&5
save_LIBS="$LIBS"
save_LDFLAGS="$LDFLAGS"
save_CPPFLAGS="$CPPFLAGS"
LDFLAGS="$LDFLAGS $OPENSSL_LDFLAGS"
LIBS="$OPENSSL_LIBS $LIBS"
CPPFLAGS="$OPENSSL_INCLUDES $CPPFLAGS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <openssl/ssl.h>
int
main ()
{
SSL_new(NULL)
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
$as_echo "#define HAVE_SSL 1" >>confdefs.h
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
CPPFLAGS="$save_CPPFLAGS"
LDFLAGS="$save_LDFLAGS"
LIBS="$save_LIBS"
LDFLAGS="$LDFLAGS $OPENSSL_LDFLAGS"
LIBS="$OPENSSL_LIBS $LIBS"
CPPFLAGS="$OPENSSL_INCLUDES $CPPFLAGS"
# Check for TCP_CONGESTION sockopt (believed to be Linux and FreeBSD only)
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking TCP_CONGESTION socket option" >&5
$as_echo_n "checking TCP_CONGESTION socket option... " >&6; }

Просмотреть файл

@ -25,6 +25,7 @@
# Initialize the autoconf system for the specified tool, version and mailing list
AC_INIT(iperf, 3-CURRENT, https://github.com/esnet/iperf, iperf, http://software.es.net/iperf/)
m4_include([ax_check_openssl.m4])
AC_LANG(C)
# Specify where the auxiliary files created by configure should go. The config
@ -97,6 +98,14 @@ AC_CHECK_HEADERS([netinet/sctp.h],
#endif
])
# Check for OPENSSL support
AX_CHECK_OPENSSL(
AC_DEFINE([HAVE_SSL], [1], [OpenSSL Is Available])
)
LDFLAGS="$LDFLAGS $OPENSSL_LDFLAGS"
LIBS="$OPENSSL_LIBS $LIBS"
CPPFLAGS="$OPENSSL_INCLUDES $CPPFLAGS"
# Check for TCP_CONGESTION sockopt (believed to be Linux and FreeBSD only)
AC_CACHE_CHECK([TCP_CONGESTION socket option],
[iperf3_cv_header_tcp_congestion],

Просмотреть файл

@ -110,7 +110,15 @@ the executable.
-1, --one-off
handle one client connection, then exit.
--rsa-private-key-path (if built with OpenSSL support)
path to the RSA private key used to decrypt authentication
credentials (not password protected)
--authorized-users-path (if built with OpenSSL support)
path to the configuration file containing authorized users
credendientals to run iperf tests. File is a comma separated
list of usernames and password hashes.
CLIENT SPECIFIC OPTIONS
-c, --client host
@ -235,8 +243,48 @@ the executable.
will be in human-readable format). If the client is run with
--json, the server output is included in a JSON object; other-
wise it is appended at the bottom of the human-readable output.
--username (if built with OpenSSL support)
username assigned by server adminitrators to access to the iperf
service.
--rsa-public-key-path (if built with OpenSSL support)
path to the RSA public key used to encrypt authentication
credentials
EXAMPLES
Authentication - RSA Keypair
Authentication feature requires a pair of public and private RSA
keys. The public key is used to encrypt the authentication
token containing the user credentials, the private key is used
to decrypt the authentication token.
An example of linux command to generate correct keypair follows:
$> openssl genrsa -des3 -out private.pem 2048
$> openssl rsa -in private.pem -outform PEM -pubout \
-out public.pem
$> openssl rsa -in private.pem -out private_not_protected.pem \
-outform PEM
Authentication - Authorized users configuration file
A simple plaintext file can be provided to iperf3 server in
order to specify the authorized user c redentials allowd to use
iperf3 server. File can contain commented lines (starting with
# char) and is a simple list of comma separated pair of
username password hash. Password hash is a sha256 hash of
string "{$user}$password":
$> S_USER=mario S_PASSWD=rossi
$> echo -ne "{$S_USER}$S_PASSWD"|sha256sum|awk '{ print $1 }'
$> cat credentials.csv
# file format: username,sha256
mario,44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c0....
$>
AUTHORS
A list of the contributors to iperf3 can be found within the documenta-
tion located at http://software.es.net/iperf/dev.html#authors.
@ -247,7 +295,7 @@ the executable.
ESnet January 2017 IPERF3(1)
ESnet Januar 2017 IPERF3(1)
The iperf3 manual page will typically be installed in manual
section 1.

Просмотреть файл

@ -10,7 +10,9 @@ Source0: http://stats.es.net/software/iperf-%{version}.tar.gz
BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)
%if 0%{?el5}
BuildRequires: e2fsprogs-devel
BuildRequires: e2fsprogs-devel, openssl-devel
%else
BuildRequires: openssl-devel
%endif
%description

Просмотреть файл

@ -138,9 +138,9 @@ am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \
LTLIBRARIES = $(lib_LTLIBRARIES)
libiperf_la_LIBADD =
am_libiperf_la_OBJECTS = cjson.lo iperf_api.lo iperf_error.lo \
iperf_client_api.lo iperf_locale.lo iperf_server_api.lo \
iperf_tcp.lo iperf_udp.lo iperf_sctp.lo iperf_util.lo dscp.lo \
net.lo tcp_info.lo tcp_window_size.lo timer.lo units.lo
iperf_client_api.lo iperf_locale.lo iperf_auth.lo iperf_server_api.lo \
iperf_tcp.lo iperf_udp.lo iperf_sctp.lo iperf_util.lo dscp.lo net.lo \
tcp_info.lo tcp_window_size.lo timer.lo units.lo
libiperf_la_OBJECTS = $(am_libiperf_la_OBJECTS)
AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
@ -158,6 +158,7 @@ am__objects_1 = iperf3_profile-cjson.$(OBJEXT) \
iperf3_profile-iperf_error.$(OBJEXT) \
iperf3_profile-iperf_client_api.$(OBJEXT) \
iperf3_profile-iperf_locale.$(OBJEXT) \
iperf3_profile-iperf_auth.$(OBJEXT) \
iperf3_profile-iperf_server_api.$(OBJEXT) \
iperf3_profile-iperf_tcp.$(OBJEXT) \
iperf3_profile-iperf_udp.$(OBJEXT) \
@ -574,7 +575,9 @@ libiperf_la_SOURCES = \
iperf_api.c \
iperf_api.h \
iperf_error.c \
iperf_client_api.c \
iperf_auth.h \
iperf_auth.c \
iperf_client_api.c \
iperf_locale.c \
iperf_locale.h \
iperf_server_api.c \
@ -582,14 +585,14 @@ libiperf_la_SOURCES = \
iperf_tcp.h \
iperf_udp.c \
iperf_udp.h \
iperf_sctp.c \
iperf_sctp.h \
iperf_sctp.c \
iperf_sctp.h \
iperf_util.c \
iperf_util.h \
dscp.c \
net.c \
net.h \
portable_endian.h \
portable_endian.h \
queue.h \
tcp_info.c \
tcp_window_size.c \
@ -813,6 +816,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iperf3_profile-iperf_client_api.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iperf3_profile-iperf_error.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iperf3_profile-iperf_locale.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iperf3_profile-iperf_auth.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iperf3_profile-iperf_sctp.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iperf3_profile-iperf_server_api.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iperf3_profile-iperf_tcp.Po@am__quote@
@ -828,6 +832,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iperf_client_api.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iperf_error.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iperf_locale.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iperf_auth.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iperf_sctp.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iperf_server_api.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iperf_tcp.Plo@am__quote@
@ -961,6 +966,22 @@ iperf3_profile-iperf_locale.obj: iperf_locale.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(iperf3_profile_CFLAGS) $(CFLAGS) -c -o iperf3_profile-iperf_locale.obj `if test -f 'iperf_locale.c'; then $(CYGPATH_W) 'iperf_locale.c'; else $(CYGPATH_W) '$(srcdir)/iperf_locale.c'; fi`
iperf3_profile-iperf_auth.o: iperf_auth.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(iperf3_profile_CFLAGS) $(CFLAGS) -MT iperf3_profile-iperf_auth.o -MD -MP -MF $(DEPDIR)/iperf3_profile-iperf_auth.Tpo -c -o iperf3_profile-iperf_auth.o `test -f 'iperf_auth.c' || echo '$(srcdir)/'`iperf_auth.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/iperf3_profile-iperf_auth.Tpo $(DEPDIR)/iperf3_profile-iperf_auth.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='iperf_auth.c' object='iperf3_profile-iperf_auth.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(iperf3_profile_CFLAGS) $(CFLAGS) -c -o iperf3_profile-iperf_auth.o `test -f 'iperf_auth.c' || echo '$(srcdir)/'`iperf_auth.c
iperf3_profile-iperf_auth.obj: iperf_auth.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(iperf3_profile_CFLAGS) $(CFLAGS) -MT iperf3_profile-iperf_auth.obj -MD -MP -MF $(DEPDIR)/iperf3_profile-iperf_auth.Tpo -c -o iperf3_profile-iperf_auth.obj `if test -f 'iperf_auth.c'; then $(CYGPATH_W) 'iperf_auth.c'; else $(CYGPATH_W) '$(srcdir)/iperf_auth.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/iperf3_profile-iperf_auth.Tpo $(DEPDIR)/iperf3_profile-iperf_auth.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='iperf_auth.c' object='iperf3_profile-iperf_auth.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(iperf3_profile_CFLAGS) $(CFLAGS) -c -o iperf3_profile-iperf_auth.obj `if test -f 'iperf_auth.c'; then $(CYGPATH_W) 'iperf_auth.c'; else $(CYGPATH_W) '$(srcdir)/iperf_auth.c'; fi`
iperf3_profile-iperf_server_api.o: iperf_server_api.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(iperf3_profile_CFLAGS) $(CFLAGS) -MT iperf3_profile-iperf_server_api.o -MD -MP -MF $(DEPDIR)/iperf3_profile-iperf_server_api.Tpo -c -o iperf3_profile-iperf_server_api.o `test -f 'iperf_server_api.c' || echo '$(srcdir)/'`iperf_server_api.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/iperf3_profile-iperf_server_api.Tpo $(DEPDIR)/iperf3_profile-iperf_server_api.Po

Просмотреть файл

@ -123,6 +123,7 @@ struct iperf_settings
iperf_size_t blocks; /* number of blocks (packets) to send */
char unit_format; /* -f */
int num_ostreams; /* SCTP initmsg settings */
char *authtoken; /* Authentication token */
};
struct iperf_test;
@ -235,6 +236,8 @@ struct iperf_test
int prot_listener;
int ctrl_sck_mss; /* MSS for the control channel */
char *server_rsa_private_key;
char *server_authorized_users;
/* boolean variables for Options */
int daemon; /* -D option */

Просмотреть файл

@ -85,7 +85,14 @@ write a file with the process ID, most useful when running as a daemon.
.TP
.BR -1 ", " --one-off
handle one client connection, then exit.
.TP
.BR --rsa-private-key-path " \fIfile\fR" " (if built with OpenSSL support)
path to the RSA private key used to decrypt authentication credentials (not
password protected)
.TP
.BR --authorized-users-path " \fIfile\fR" " (if built with OpenSSL support)
path to the configuration file containing authorized users credendientals to run
iperf tests. File is a comma separated list of usernames and password hashes.
.SH "CLIENT SPECIFIC OPTIONS"
.TP
.BR -c ", " --client " \fIhost\fR"
@ -101,7 +108,7 @@ use UDP rather than TCP
.TP
.BR -b ", " --bandwidth " \fIn\fR[KM]"
set target bandwidth to \fIn\fR bits/sec (default 1 Mbit/sec for UDP, unlimited for TCP).
If there are multiple streams (\-P flag), the bandwidth limit is applied
If there are multiple streams (\-P flag), the bandwidth limit is applied
separately to each stream.
You can also add a '/' and a number to the bandwidth specifier.
This is called "burst mode".
@ -222,6 +229,45 @@ JSON format, otherwise it will be in human-readable format).
If the client is run with \fB--json\fR, the server output is included
in a JSON object; otherwise it is appended at the bottom of the
human-readable output.
.TP
.BR --username " \fIusername\fR" " (if built with OpenSSL support)
username assigned by server adminitrators to access to the iperf service.
.TP
.BR --rsa-public-key-path " \fIfile\fR" " (if built with OpenSSL support)
path to the RSA public key used to encrypt authentication credentials
.SH EXAMPLES
.TP
.BR "Authentication - RSA Keypair"
Authentication feature requires a pair of public and private RSA keys. The
public key is used to encrypt the authentication token containing the
user credentials, the private key is used to decrypt the authentication token.
An example of linux command to generate correct keypair follows:
.sp 1
.in +.5i $> openssl genrsa -des3 -out private.pem 2048
.sp 0
$> openssl rsa -in private.pem -outform PEM -pubout -out public.pem
.sp 0
$> openssl rsa -in private.pem -out private_not_protected.pem -outform PEM
.TP
.BR "Authentication - Authorized users configuration file"
A simple plaintext file can be provided to iperf3 server in order to specify
the authorized user credentials allowd to use iperf3 server. File can contain
commented lines (starting with # char) and is a simple list of comma separated
pair of username password hash. Password hash is a sha256 hash of string
"{$user}$password":
.sp 1
.in +.5i $> S_USER=mario S_PASSWD=rossi
.sp 0
$> echo -n "{$S_USER}$S_PASSWD" | sha256sum | awk '{ print $1 }'
.sp 0
$> cat credentials.csv
.sp 0
# file format: username,sha256
.sp 0
mario,44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c0....
.sp 0
$>
.SH AUTHORS
A list of the contributors to iperf3 can be found within the

Просмотреть файл

@ -77,6 +77,9 @@
#include "iperf_util.h"
#include "iperf_locale.h"
#include "version.h"
#if defined(HAVE_SSL)
#include "iperf_auth.h"
#endif /* HAVE_SSL */
/* Forwards. */
static int send_parameters(struct iperf_test *test);
@ -671,6 +674,12 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
{"get-server-output", no_argument, NULL, OPT_GET_SERVER_OUTPUT},
{"udp-counters-64bit", no_argument, NULL, OPT_UDP_COUNTERS_64BIT},
{"no-fq-socket-pacing", no_argument, NULL, OPT_NO_FQ_SOCKET_PACING},
#if defined(HAVE_SSL)
{"username", required_argument, NULL, OPT_CLIENT_USERNAME},
{"rsa-public-key-path", required_argument, NULL, OPT_CLIENT_RSA_PUBLIC_KEY},
{"rsa-private-key-path", required_argument, NULL, OPT_SERVER_RSA_PRIVATE_KEY},
{"authorized-users-path", required_argument, NULL, OPT_SERVER_AUTHORIZED_USERS},
#endif /* HAVE_SSL */
{"fq-rate", required_argument, NULL, OPT_FQ_RATE},
{"debug", no_argument, NULL, 'd'},
{"help", no_argument, NULL, 'h'},
@ -688,6 +697,10 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
blksize = 0;
server_flag = client_flag = rate_flag = duration_flag = 0;
#if defined(HAVE_SSL)
char *client_username = NULL, *client_rsa_public_key = NULL;
#endif /* HAVE_SSL */
while ((flag = getopt_long(argc, argv, "p:f:i:D1VJvsc:ub:t:n:k:l:P:Rw:B:M:N46S:L:ZO:F:A:T:C:dI:hX:", longopts, NULL)) != -1) {
switch (flag) {
case 'p':
@ -981,6 +994,20 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
return -1;
#endif
break;
#if defined(HAVE_SSL)
case OPT_CLIENT_USERNAME:
client_username = strdup(optarg);
break;
case OPT_CLIENT_RSA_PUBLIC_KEY:
client_rsa_public_key = strdup(optarg);
break;
case OPT_SERVER_RSA_PRIVATE_KEY:
test->server_rsa_private_key = strdup(optarg);
break;
case OPT_SERVER_AUTHORIZED_USERS:
test->server_authorized_users = strdup(optarg);
break;
#endif /* HAVE_SSL */
case 'h':
usage_long(stdout);
exit(0);
@ -992,23 +1019,64 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
/* Set logging to a file if specified, otherwise use the default (stdout) */
if (test->logfile) {
test->outfile = fopen(test->logfile, "a+");
if (test->outfile == NULL) {
i_errno = IELOGFILE;
return -1;
}
test->outfile = fopen(test->logfile, "a+");
if (test->outfile == NULL) {
i_errno = IELOGFILE;
return -1;
}
}
/* Check flag / role compatibility. */
if (test->role == 'c' && server_flag) {
i_errno = IESERVERONLY;
return -1;
i_errno = IESERVERONLY;
return -1;
}
if (test->role == 's' && client_flag) {
i_errno = IECLIENTONLY;
return -1;
i_errno = IECLIENTONLY;
return -1;
}
#if defined(HAVE_SSL)
if (test->role == 's' && (client_username || client_rsa_public_key)){
i_errno = IECLIENTONLY;
return -1;
} else if (test->role == 'c' && (client_username || client_rsa_public_key) &&
!(client_username && client_rsa_public_key)) {
i_errno = IESETCLIENTAUTH;
return -1;
} else if (test->role == 'c' && (client_username && client_rsa_public_key)){
char *client_password = NULL;
size_t s;
if (iperf_getpass(&client_password, &s, stdin) < 0){
return -1;
}
if (strlen(client_username) > 20 || strlen(client_password) > 20){
i_errno = IESETCLIENTAUTH;
return -1;
}
if (test_load_pubkey(client_rsa_public_key) < 0){
i_errno = IESETCLIENTAUTH;
return -1;
}
encode_auth_setting(client_username, client_password, client_rsa_public_key, &test->settings->authtoken);
}
if (test->role == 'c' && (test->server_rsa_private_key || test->server_authorized_users)){
i_errno = IESERVERONLY;
return -1;
} else if (test->role == 's' && (test->server_rsa_private_key || test->server_authorized_users) &&
!(test->server_rsa_private_key && test->server_authorized_users)) {
i_errno = IESETSERVERAUTH;
return -1;
} else if (test->role == 's' && test->server_rsa_private_key && test_load_private_key(test->server_rsa_private_key) < 0){
i_errno = IESETSERVERAUTH;
return -1;
}
#endif //HAVE_SSL
if (!test->bind_address && test->bind_port) {
i_errno = IEBIND;
return -1;
@ -1235,6 +1303,29 @@ iperf_create_send_timers(struct iperf_test * test)
return 0;
}
#if defined(HAVE_SSL)
int test_is_authorized(struct iperf_test *test){
if ( !(test->server_rsa_private_key && test->server_authorized_users)) {
return 0;
}
if (test->settings->authtoken){
char *username = NULL, *password = NULL;
time_t ts;
decode_auth_setting(test->debug, test->settings->authtoken, test->server_rsa_private_key, &username, &password, &ts);
int ret = check_authentication(username, password, ts, test->server_authorized_users);
if (ret == 0){
iperf_printf(test, report_authetication_successed, username, ts);
return 0;
} else {
iperf_printf(test, report_authetication_failed, username, ts);
return -1;
}
}
return -1;
}
#endif //HAVE_SSL
/**
* iperf_exchange_parameters - handles the param_Exchange part for client
*
@ -1256,8 +1347,22 @@ iperf_exchange_parameters(struct iperf_test *test)
if (get_parameters(test) < 0)
return -1;
#if defined(HAVE_SSL)
if (test_is_authorized(test) < 0){
if (iperf_set_send_state(test, SERVER_ERROR) != 0)
return -1;
i_errno = IEAUTHTEST;
err = htonl(i_errno);
if (Nwrite(test->ctrl_sck, (char*) &err, sizeof(err), Ptcp) < 0) {
i_errno = IECTRLWRITE;
return -1;
}
return -1;
}
#endif //HAVE_SSL
if ((s = test->protocol->listen(test)) < 0) {
if (iperf_set_send_state(test, SERVER_ERROR) != 0)
if (iperf_set_send_state(test, SERVER_ERROR) != 0)
return -1;
err = htonl(i_errno);
if (Nwrite(test->ctrl_sck, (char*) &err, sizeof(err), Ptcp) < 0) {
@ -1366,7 +1471,10 @@ send_parameters(struct iperf_test *test)
cJSON_AddNumberToObject(j, "get_server_output", iperf_get_test_get_server_output(test));
if (test->udp_counters_64bit)
cJSON_AddNumberToObject(j, "udp_counters_64bit", iperf_get_test_udp_counters_64bit(test));
#if defined(HAVE_SSL)
if (test->settings->authtoken)
cJSON_AddStringToObject(j, "authtoken", test->settings->authtoken);
#endif // HAVE_SSL
cJSON_AddStringToObject(j, "client_version", IPERF_VERSION);
if (test->debug) {
@ -1448,7 +1556,10 @@ get_parameters(struct iperf_test *test)
iperf_set_test_get_server_output(test, 1);
if ((j_p = cJSON_GetObjectItem(j, "udp_counters_64bit")) != NULL)
iperf_set_test_udp_counters_64bit(test, 1);
#if defined(HAVE_SSL)
if ((j_p = cJSON_GetObjectItem(j, "authtoken")) != NULL)
test->settings->authtoken = strdup(j_p->valuestring);
#endif //HAVE_SSL
if (test->sender && test->protocol->id == Ptcp && has_tcpinfo_retransmits())
test->sender_has_retransmits = 1;
cJSON_Delete(j);
@ -2764,8 +2875,18 @@ iperf_new_stream(struct iperf_test *test, int s)
if (test->tmp_template) {
snprintf(template, sizeof(template) / sizeof(char), "%s", test->tmp_template);
} else {
char buf[] = "/tmp/iperf3.XXXXXX";
snprintf(template, sizeof(template) / sizeof(char), "%s", buf);
//find the system temporary dir *unix, windows, cygwin support
char* tempdir = getenv("TMPDIR");
if (tempdir == 0){
tempdir = getenv("TEMP");
}
if (tempdir == 0){
tempdir = getenv("TMP");
}
if (tempdir == 0){
tempdir = "/tmp";
}
snprintf(template, sizeof(template) / sizeof(char), "%s/iperf3.XXXXXX", tempdir);
}
sp = (struct iperf_stream *) malloc(sizeof(struct iperf_stream));

Просмотреть файл

@ -54,6 +54,10 @@ struct iperf_stream;
#define OPT_NO_FQ_SOCKET_PACING 9 /* UNUSED */
#define OPT_FQ_RATE 10
#define OPT_DSCP 11
#define OPT_CLIENT_USERNAME 12
#define OPT_CLIENT_RSA_PUBLIC_KEY 13
#define OPT_SERVER_RSA_PRIVATE_KEY 14
#define OPT_SERVER_AUTHORIZED_USERS 15
/* states */
#define TEST_START 1
@ -295,6 +299,8 @@ enum {
IEBIND = 19, // Local port specified with no local bind option
IEUDPBLOCKSIZE = 20, // Block size invalid
IEBADTOS = 21, // Bad TOS value
IESETCLIENTAUTH = 22, // Bad configuration of client authentication
IESETSERVERAUTH = 23, // Bad configuration of server authentication
/* Test errors */
IENEWTEST = 100, // Unable to create a new test (check perror)
IEINITTEST = 101, // Test initialization failed (check perror)
@ -338,6 +344,7 @@ enum {
IESETSCTPBINDX= 139, // Unable to process sctp_bindx() parameters
IESETPACING= 140, // Unable to set socket pacing rate
IESETBUF2= 141, // Socket buffer size incorrect (written value != read value)
IEAUTHTEST = 142, // Test authorization failed
/* Stream errors */
IECREATESTREAM = 200, // Unable to create a new stream (check herror/perror)
IEINITSTREAM = 201, // Unable to initialize stream (check herror/perror)

312
src/iperf_auth.c Обычный файл
Просмотреть файл

@ -0,0 +1,312 @@
/*
* iperf, Copyright (c) 2014-2017, The Regents of the University of
* California, through Lawrence Berkeley National Laboratory (subject
* to receipt of any required approvals from the U.S. Dept. of
* Energy). All rights reserved.
*
* If you have questions about your rights to use or distribute this
* software, please contact Berkeley Lab's Technology Transfer
* Department at TTD@lbl.gov.
*
* NOTICE. This software is owned by the U.S. Department of Energy.
* As such, the U.S. Government has been granted for itself and others
* acting on its behalf a paid-up, nonexclusive, irrevocable,
* worldwide license in the Software to reproduce, prepare derivative
* works, and perform publicly and display publicly. Beginning five
* (5) years after the date permission to assert copyright is obtained
* from the U.S. Department of Energy, and subject to any subsequent
* five (5) year renewals, the U.S. Government is granted for itself
* and others acting on its behalf a paid-up, nonexclusive,
* irrevocable, worldwide license in the Software to reproduce,
* prepare derivative works, distribute copies to the public, perform
* publicly and display publicly, and to permit others to do so.
*
* This code is distributed under a BSD style license, see the LICENSE file
* for complete information.
*/
#include "iperf_config.h"
#include <string.h>
#include <assert.h>
#include <time.h>
#include <sys/types.h>
#include <stdio.h>
#include <termios.h>
#if defined(HAVE_SSL)
#include <openssl/bio.h>
#include <openssl/pem.h>
#include <openssl/sha.h>
#include <openssl/buffer.h>
void sha256(const char *string, char outputBuffer[65])
{
unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256_CTX sha256;
SHA256_Init(&sha256);
SHA256_Update(&sha256, string, strlen(string));
SHA256_Final(hash, &sha256);
int i = 0;
for(i = 0; i < SHA256_DIGEST_LENGTH; i++)
{
sprintf(outputBuffer + (i * 2), "%02x", hash[i]);
}
outputBuffer[64] = 0;
}
int check_authentication(const char *username, const char *password, const time_t ts, const char *filename){
time_t t = time(NULL);
time_t utc_seconds = mktime(localtime(&t));
if ( (utc_seconds - ts) < 10 && (utc_seconds - ts) > 0 ){
return 1;
}
char passwordHash[65];
char salted[strlen(username) + strlen(password) + 3];
sprintf(salted, "{%s}%s", username, password);
sha256(&salted[0], passwordHash);
char *s_username, *s_password;
int i;
FILE *ptr_file;
char buf[1024];
ptr_file =fopen(filename,"r");
if (!ptr_file)
return 2;
while (fgets(buf,1024, ptr_file)){
//strip the \n or \r\n chars
for (i = 0; buf[i] != '\0'; i++){
if (buf[i] == '\n' || buf[i] == '\r'){
buf[i] = '\0';
break;
}
}
//skip empty / not completed / comment lines
if (strlen(buf) == 0 || strchr(buf, ',') == NULL || buf[0] == '#'){
continue;
}
s_username = strtok(buf, ",");
s_password = strtok(NULL, ",");
if (strcmp( username, s_username ) == 0 && strcmp( passwordHash, s_password ) == 0){
return 0;
}
}
return 3;
}
int Base64Encode(unsigned char* buffer, const size_t length, char** b64text) { //Encodes a binary safe base 64 string
BIO *bio, *b64;
BUF_MEM *bufferPtr;
b64 = BIO_new(BIO_f_base64());
bio = BIO_new(BIO_s_mem());
bio = BIO_push(b64, bio);
BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); //Ignore newlines - write everything in one line
BIO_write(bio, buffer, length);
BIO_flush(bio);
BIO_get_mem_ptr(bio, &bufferPtr);
BIO_set_close(bio, BIO_NOCLOSE);
BIO_free_all(bio);
*b64text=(*bufferPtr).data;
(*b64text)[(*bufferPtr).length] = '\0';
return (0); //success
}
size_t calcDecodeLength(const char* b64input) { //Calculates the length of a decoded string
size_t len = strlen(b64input), padding = 0;
if (b64input[len-1] == '=' && b64input[len-2] == '=') //last two chars are =
padding = 2;
else if (b64input[len-1] == '=') //last char is =
padding = 1;
return (len*3)/4 - padding;
}
int Base64Decode(char* b64message, unsigned char** buffer, size_t* length) { //Decodes a base64 encoded string
BIO *bio, *b64;
int decodeLen = calcDecodeLength(b64message);
*buffer = (unsigned char*)malloc(decodeLen + 1);
(*buffer)[decodeLen] = '\0';
bio = BIO_new_mem_buf(b64message, -1);
b64 = BIO_new(BIO_f_base64());
bio = BIO_push(b64, bio);
BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); //Do not use newlines to flush buffer
*length = BIO_read(bio, *buffer, strlen(b64message));
assert(*length == decodeLen); //length should equal decodeLen, else something went horribly wrong
BIO_free_all(bio);
return (0); //success
}
EVP_PKEY *load_pubkey(const char *file) {
BIO *key = NULL;
EVP_PKEY *pkey = NULL;
key = BIO_new_file(file, "r");
pkey = PEM_read_bio_PUBKEY(key, NULL, NULL, NULL);
BIO_free(key);
return (pkey);
}
EVP_PKEY *load_key(const char *file) {
BIO *key = NULL;
EVP_PKEY *pkey = NULL;
key = BIO_new_file(file, "r");
pkey = PEM_read_bio_PrivateKey(key, NULL, NULL, NULL);
BIO_free(key);
return (pkey);
}
int test_load_pubkey(const char *file){
EVP_PKEY *key = load_pubkey(file);
if (key == NULL){
return -1;
}
EVP_PKEY_free(key);
return 0;
}
int test_load_private_key(const char *file){
EVP_PKEY *key = load_key(file);
if (key == NULL){
return -1;
}
EVP_PKEY_free(key);
return 0;
}
int encrypt_rsa_message(const char *plaintext, const char *public_keyfile, unsigned char **encryptedtext) {
EVP_PKEY *public_key = NULL;
RSA *rsa = NULL;
unsigned char *rsa_buffer = NULL, pad = RSA_PKCS1_PADDING;
int keysize, encryptedtext_len, rsa_buffer_len;
public_key = load_pubkey(public_keyfile);
rsa = EVP_PKEY_get1_RSA(public_key);
EVP_PKEY_free(public_key);
keysize = RSA_size(rsa);
rsa_buffer = OPENSSL_malloc(keysize * 2);
*encryptedtext = (unsigned char*)OPENSSL_malloc(keysize);
BIO *bioBuff = BIO_new_mem_buf((void*)plaintext, (int)strlen(plaintext));
rsa_buffer_len = BIO_read(bioBuff, rsa_buffer, keysize * 2);
encryptedtext_len = RSA_public_encrypt(rsa_buffer_len, rsa_buffer, *encryptedtext, rsa, pad);
RSA_free(rsa);
OPENSSL_free(rsa_buffer);
OPENSSL_free(bioBuff);
return encryptedtext_len;
}
int decrypt_rsa_message(const unsigned char *encryptedtext, const int encryptedtext_len, const char *private_keyfile, unsigned char **plaintext) {
EVP_PKEY *private_key = NULL;
RSA *rsa = NULL;
unsigned char *rsa_buffer = NULL, pad = RSA_PKCS1_PADDING;
int plaintext_len, rsa_buffer_len, keysize;
private_key = load_key(private_keyfile);
rsa = EVP_PKEY_get1_RSA(private_key);
EVP_PKEY_free(private_key);
keysize = RSA_size(rsa);
rsa_buffer = OPENSSL_malloc(keysize * 2);
*plaintext = (unsigned char*)OPENSSL_malloc(keysize);
BIO *bioBuff = BIO_new_mem_buf((void*)encryptedtext, encryptedtext_len);
rsa_buffer_len = BIO_read(bioBuff, rsa_buffer, keysize * 2);
plaintext_len = RSA_private_decrypt(rsa_buffer_len, rsa_buffer, *plaintext, rsa, pad);
RSA_free(rsa);
OPENSSL_free(rsa_buffer);
OPENSSL_free(bioBuff);
return plaintext_len;
}
int encode_auth_setting(const char *username, const char *password, const char *public_keyfile, char **authtoken){
time_t t = time(NULL);
time_t utc_seconds = mktime(localtime(&t));
char text[150];
sprintf (text, "user: %s\npwd: %s\nts: %ld", username, password, utc_seconds);
unsigned char *encrypted = NULL;
int encrypted_len;
encrypted_len = encrypt_rsa_message(text, public_keyfile, &encrypted);
Base64Encode(encrypted, encrypted_len, authtoken);
return (0); //success
}
int decode_auth_setting(int enable_debug, char *authtoken, const char *private_keyfile, char **username, char **password, time_t *ts){
unsigned char *encrypted_b64 = NULL;
size_t encrypted_len_b64;
Base64Decode(authtoken, &encrypted_b64, &encrypted_len_b64);
unsigned char *plaintext = NULL;
int plaintext_len;
plaintext_len = decrypt_rsa_message(encrypted_b64, encrypted_len_b64, private_keyfile, &plaintext);
plaintext[plaintext_len] = '\0';
char s_username[20], s_password[20];
sscanf ((char *)plaintext,"user: %s\npwd: %s\nts: %ld", s_username, s_password, ts);
if (enable_debug) {
printf("Auth Token Content:\n%s\n", plaintext);
printf("Auth Token Credentials:\n--> %s %s\n", s_username, s_password);
}
*username = (char *) calloc(21, sizeof(char *));
*password = (char *) calloc(21, sizeof(char *));
strncpy(*username, s_username, 20);
strncpy(*password, s_password, 20);
return (0);
}
#endif //HAVE_SSL
ssize_t iperf_getpass (char **lineptr, size_t *n, FILE *stream) {
struct termios old, new;
ssize_t nread;
/* Turn echoing off and fail if we can't. */
if (tcgetattr (fileno (stream), &old) != 0)
return -1;
new = old;
new.c_lflag &= ~ECHO;
if (tcsetattr (fileno (stream), TCSAFLUSH, &new) != 0)
return -1;
/* Read the password. */
printf("Password: ");
nread = getline (lineptr, n, stream);
/* Restore terminal. */
(void) tcsetattr (fileno (stream), TCSAFLUSH, &old);
//strip the \n or \r\n chars
char *buf = *lineptr;
int i;
for (i = 0; buf[i] != '\0'; i++){
if (buf[i] == '\n' || buf[i] == '\r'){
buf[i] = '\0';
break;
}
}
return nread;
}

36
src/iperf_auth.h Обычный файл
Просмотреть файл

@ -0,0 +1,36 @@
/*
* iperf, Copyright (c) 2014-2017, The Regents of the University of
* California, through Lawrence Berkeley National Laboratory (subject
* to receipt of any required approvals from the U.S. Dept. of
* Energy). All rights reserved.
*
* If you have questions about your rights to use or distribute this
* software, please contact Berkeley Lab's Technology Transfer
* Department at TTD@lbl.gov.
*
* NOTICE. This software is owned by the U.S. Department of Energy.
* As such, the U.S. Government has been granted for itself and others
* acting on its behalf a paid-up, nonexclusive, irrevocable,
* worldwide license in the Software to reproduce, prepare derivative
* works, and perform publicly and display publicly. Beginning five
* (5) years after the date permission to assert copyright is obtained
* from the U.S. Department of Energy, and subject to any subsequent
* five (5) year renewals, the U.S. Government is granted for itself
* and others acting on its behalf a paid-up, nonexclusive,
* irrevocable, worldwide license in the Software to reproduce,
* prepare derivative works, distribute copies to the public, perform
* publicly and display publicly, and to permit others to do so.
*
* This code is distributed under a BSD style license, see the LICENSE file
* for complete information.
*/
#include <time.h>
#include <sys/types.h>
int test_load_pubkey(const char *public_keyfile);
int test_load_private_key(const char *private_keyfile);
int encode_auth_setting(const char *username, const char *password, const char *public_keyfile, char **authtoken);
int decode_auth_setting(int enable_debug, const char *authtoken, const char *private_keyfile, char **username, char **password, time_t *ts);
int check_authentication(const char *username, const char *password, const time_t ts, const char *filename);
ssize_t iperf_getpass (char **lineptr, size_t *n, FILE *stream);

Просмотреть файл

@ -30,6 +30,9 @@
/* Define to 1 if you have the `sendfile' function. */
#undef HAVE_SENDFILE
/* Define to 1 if you have the OPENSSL suppoert */
#undef HAVE_SSL
/* Have SO_MAX_PACING_RATE sockopt. */
#undef HAVE_SO_MAX_PACING_RATE

Просмотреть файл

@ -128,9 +128,15 @@ iperf_strerror(int i_errno)
case IEUDPBLOCKSIZE:
snprintf(errstr, len, "block size invalid (minimum = %d bytes, maximum = %d bytes)", MIN_UDP_BLOCKSIZE, MAX_UDP_BLOCKSIZE);
break;
case IEBADTOS:
snprintf(errstr, len, "bad TOS value (must be between 0 and 255 inclusive)");
break;
case IEBADTOS:
snprintf(errstr, len, "bad TOS value (must be between 0 and 255 inclusive)");
break;
case IESETCLIENTAUTH:
snprintf(errstr, len, "you must specify username (max 20 chars), password (max 20 chars) and a path to a valid public rsa client to be used");
break;
case IESETSERVERAUTH:
snprintf(errstr, len, "you must specify path to a valid private rsa server to be used and a user credential file");
break;
case IEMSS:
snprintf(errstr, len, "TCP MSS too large (maximum = %d bytes)", MAX_MSS);
break;
@ -168,6 +174,9 @@ iperf_strerror(int i_errno)
snprintf(errstr, len, "test initialization failed");
perr = 1;
break;
case IEAUTHTEST:
snprintf(errstr, len, "test authorization failed");
break;
case IELISTEN:
snprintf(errstr, len, "unable to start listener for connections");
perr = 1;

Просмотреть файл

@ -117,6 +117,11 @@ const char usage_longstr[] = "Usage: iperf3 [-s|-c host] [options]\n"
" -D, --daemon run the server as a daemon\n"
" -I, --pidfile file write PID file\n"
" -1, --one-off handle one client connection then exit\n"
#if defined(HAVE_SSL)
" --rsa-private-key-path path to the RSA private key used to decrypt authentication credentials\n"
" --authorized-users-path path to the configuration file containing user credendial authorized to use iperf server\n"
" file with username and password comma separated, one per line\n"
#endif //HAVE_SSL
"Client specific:\n"
" -c, --client <host> run in client mode, connecting to <host>\n"
#if defined(HAVE_SCTP)
@ -158,7 +163,11 @@ const char usage_longstr[] = "Usage: iperf3 [-s|-c host] [options]\n"
" -T, --title str prefix every output line with this string\n"
" --get-server-output get results from server\n"
" --udp-counters-64bit use 64-bit counters in UDP test packets\n"
#if defined(HAVE_SSL)
" --username username to access to the server test\n"
" --rsa-public-key-path path to the RSA public key used to encrypt authentication credentials\n"
#endif //HAVESSL
#ifdef NOT_YET_SUPPORTED /* still working on these */
#endif
@ -249,6 +258,12 @@ const char report_time[] =
const char report_connecting[] =
"Connecting to host %s, port %d\n";
const char report_authetication_successed[] =
"Authentication successed for user '%s' ts %ld\n";
const char report_authetication_failed[] =
"Authentication failed for user '%s' ts %ld\n";
const char report_reverse[] =
"Reverse mode, remote host %s is sending\n";

Просмотреть файл

@ -54,6 +54,8 @@ extern const char report_reverse[] ;
extern const char report_accepted[] ;
extern const char report_cookie[] ;
extern const char report_connected[] ;
extern const char report_authetication_successed[] ;
extern const char report_authetication_failed[] ;
extern const char report_window[] ;
extern const char report_autotune[] ;
extern const char report_omit_done[] ;