aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.in35
-rwxr-xr-xsrc/iperf.h3
-rw-r--r--src/iperf3.150
-rwxr-xr-xsrc/iperf_api.c149
-rwxr-xr-xsrc/iperf_api.h7
-rw-r--r--src/iperf_auth.c312
-rw-r--r--src/iperf_auth.h36
-rw-r--r--src/iperf_config.h.in3
-rw-r--r--src/iperf_error.c15
-rw-r--r--src/iperf_locale.c17
-rw-r--r--src/iperf_locale.h2
11 files changed, 602 insertions, 27 deletions
diff --git a/src/Makefile.in b/src/Makefile.in
index dca6cdd..dd29a2d 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -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
diff --git a/src/iperf.h b/src/iperf.h
index 9ee7ea7..5073ad9 100755
--- a/src/iperf.h
+++ b/src/iperf.h
@@ -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 */
diff --git a/src/iperf3.1 b/src/iperf3.1
index 2d89f11..48d58e2 100644
--- a/src/iperf3.1
+++ b/src/iperf3.1
@@ -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
diff --git a/src/iperf_api.c b/src/iperf_api.c
index 73b8e5a..61971ec 100755
--- a/src/iperf_api.c
+++ b/src/iperf_api.c
@@ -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));
diff --git a/src/iperf_api.h b/src/iperf_api.h
index 80e169c..4b172c5 100755
--- a/src/iperf_api.h
+++ b/src/iperf_api.h
@@ -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)
diff --git a/src/iperf_auth.c b/src/iperf_auth.c
new file mode 100644
index 0000000..d42a471
--- /dev/null
+++ b/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;
+}
+
+
diff --git a/src/iperf_auth.h b/src/iperf_auth.h
new file mode 100644
index 0000000..38971d8
--- /dev/null
+++ b/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);
diff --git a/src/iperf_config.h.in b/src/iperf_config.h.in
index 6da34e7..07e3e6c 100644
--- a/src/iperf_config.h.in
+++ b/src/iperf_config.h.in
@@ -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
diff --git a/src/iperf_error.c b/src/iperf_error.c
index 90b91e0..3e20f1e 100644
--- a/src/iperf_error.c
+++ b/src/iperf_error.c
@@ -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;
diff --git a/src/iperf_locale.c b/src/iperf_locale.c
index 6277808..700218d 100644
--- a/src/iperf_locale.c
+++ b/src/iperf_locale.c
@@ -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";
diff --git a/src/iperf_locale.h b/src/iperf_locale.h
index 4bfd99b..e1c8383 100644
--- a/src/iperf_locale.h
+++ b/src/iperf_locale.h
@@ -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[] ;