From 52844e057b1bb1b751beca0fce83cdd60a2504d6 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Tue, 14 Feb 2012 19:02:40 +0100 Subject: Added DTLS-stress test. Contributed by Sean Buckheister. --- tests/dtls/Makefile.am | 47 +++ tests/dtls/dtls | 33 ++ tests/dtls/dtls-stress.c | 766 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 846 insertions(+) create mode 100644 tests/dtls/Makefile.am create mode 100755 tests/dtls/dtls create mode 100644 tests/dtls/dtls-stress.c (limited to 'tests/dtls') diff --git a/tests/dtls/Makefile.am b/tests/dtls/Makefile.am new file mode 100644 index 0000000000..1dda703f92 --- /dev/null +++ b/tests/dtls/Makefile.am @@ -0,0 +1,47 @@ +## Process this file with automake to produce Makefile.in +# Copyright (C) 2012 Free Software Foundation, Inc. +# +# Author: Nikos Mavrogiannopoulos +# +# This file is part of GnuTLS. +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this file; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +dist_check_SCRIPTS = dtls + +AM_CFLAGS = $(WARN_CFLAGS) $(WERROR_CFLAGS) +AM_CPPFLAGS = \ + -I$(top_srcdir)/gl \ + -I$(top_builddir)/gl \ + -I$(top_srcdir)/lib/includes \ + -I$(top_builddir)/lib/includes \ + -I$(top_srcdir)/extra/includes \ + -I$(top_builddir)/extra/includes \ + -I$(top_srcdir)/lib \ + -I$(top_srcdir)/doc/examples + +AM_LDFLAGS = -no-install +LDADD = ../../lib/libgnutls.la \ + ../../gl/libgnu.la \ + $(LIBSOCKET) $(INET_NTOP_LIB) $(INET_PTON_LIB) + +if !WINDOWS + +check_PROGRAMS = dtls-stress +TESTS = dtls + +endif + +TESTS_ENVIRONMENT = EXEEXT=$(EXEEXT) diff --git a/tests/dtls/dtls b/tests/dtls/dtls new file mode 100755 index 0000000000..ec00897edc --- /dev/null +++ b/tests/dtls/dtls @@ -0,0 +1,33 @@ +#!/bin/sh + +# Copyright (C) 2006-2008, 2010, 2012 Free Software Foundation, Inc. +# +# Author: Simon Josefsson +# +# This file is part of GnuTLS. +# +# GnuTLS is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at +# your option) any later version. +# +# GnuTLS is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GnuTLS; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +set -e + +if test "${WINDIR}" != "";then + exit 77 +fi + +./dtls-stress -shello 021 -sfinished 01 -cfinished 012 SKeyExchange CKeyExchange CFinished +./dtls-stress -shello 012 -sfinished 10 -cfinished 210 SHello SKeyExchange SHelloDone +./dtls-stress -shello 012 -sfinished 01 -cfinished 021 SHello SKeyExchange SHelloDone + +exit 0 diff --git a/tests/dtls/dtls-stress.c b/tests/dtls/dtls-stress.c new file mode 100644 index 0000000000..6857636730 --- /dev/null +++ b/tests/dtls/dtls-stress.c @@ -0,0 +1,766 @@ +/* + * Copyright (C) 2012 Sean Buckheister + * + * This file is part of GnuTLS. + * + * GnuTLS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GnuTLS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GnuTLS; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum role { + SERVER, + CLIENT +} role; + +int debug; +int nonblock; + +int run_id; + +const char* role_to_name(enum role role) +{ + if (role == SERVER) { + return "server"; + } else { + return "client"; + } +} + +void logfn(int level, const char* s) +{ + if (debug) { + fprintf(stdout, "%i %s|<%i> %s", run_id, role_to_name(role), level, s); + } +} + +void auditfn(gnutls_session_t session, const char* s) +{ + if (debug) { + fprintf(stdout, "%i %s| %s", run_id, role_to_name(role), s); + } +} + +void drop(const char* packet) +{ + if (debug) { + fprintf(stdout, "%i %s| dropping %s\n", run_id, role_to_name(role), packet); + } +} + + +typedef struct { + int count; +} filter_packet_state_t; + +filter_packet_state_t state_packet_ServerHello = { 0 }; +filter_packet_state_t state_packet_ServerKeyExchange = { 0 }; +filter_packet_state_t state_packet_ServerHelloDone = { 0 }; +filter_packet_state_t state_packet_ClientKeyExchange = { 0 }; +filter_packet_state_t state_packet_ClientChangeCipherSpec = { 0 }; +filter_packet_state_t state_packet_ClientFinished = { 0 }; +filter_packet_state_t state_packet_ServerChangeCipherSpec = { 0 }; +filter_packet_state_t state_packet_ServerFinished = { 0 }; + +typedef struct { + gnutls_datum_t packets[3]; + int* order; + int count; +} filter_permute_state_t; + +filter_permute_state_t state_permute_ServerHello = { { { 0, 0 }, { 0, 0 }, { 0, 0 } }, 0, 0 }; +filter_permute_state_t state_permute_ServerFinished = { { { 0, 0 }, { 0, 0 }, { 0, 0 } }, 0, 0 }; +filter_permute_state_t state_permute_ClientFinished = { { { 0, 0 }, { 0, 0 }, { 0, 0 } }, 0, 0 }; + +typedef void (*filter_fn)(gnutls_transport_ptr_t, const unsigned char*, size_t); + +filter_fn filter_chain[32]; +int filter_current_idx; + +void filter_clear_state() +{ + memset(&state_packet_ServerHello, 0, sizeof(state_packet_ServerHello)); + memset(&state_packet_ServerKeyExchange, 0, sizeof(state_packet_ServerKeyExchange)); + memset(&state_packet_ServerHelloDone, 0, sizeof(state_packet_ServerHelloDone)); + memset(&state_packet_ClientKeyExchange, 0, sizeof(state_packet_ClientKeyExchange)); + memset(&state_packet_ClientChangeCipherSpec, 0, sizeof(state_packet_ClientChangeCipherSpec)); + memset(&state_packet_ServerChangeCipherSpec, 0, sizeof(state_packet_ServerChangeCipherSpec)); + memset(&state_packet_ServerFinished, 0, sizeof(state_packet_ServerFinished)); + + for (int i = 0; i < 3; i++) { + if (state_permute_ServerHello.packets[i].data) { + free(state_permute_ServerHello.packets[i].data); + } + if (state_permute_ServerFinished.packets[i].data) { + free(state_permute_ServerFinished.packets[i].data); + } + if (state_permute_ClientFinished.packets[i].data) { + free(state_permute_ClientFinished.packets[i].data); + } + } + + memset(&state_permute_ServerHello, 0, sizeof(state_permute_ServerHello)); + memset(&state_permute_ServerFinished, 0, sizeof(state_permute_ServerFinished)); + memset(&state_permute_ClientFinished, 0, sizeof(state_permute_ClientFinished)); +} + +void filter_run_next(gnutls_transport_ptr_t fd, + const unsigned char* buffer, size_t len) +{ + filter_fn fn = filter_chain[filter_current_idx]; + filter_current_idx++; + if (fn) { + fn(fd, buffer, len); + } else { + send((long int) fd, buffer, len, 0); + } +} + + + +int match_ServerHello(const unsigned char* buffer, size_t len) +{ + return role == SERVER && len >= 13 + 1 && buffer[0] == 22 && buffer[13] == 2; +} + +void filter_packet_ServerHello(gnutls_transport_ptr_t fd, + const unsigned char* buffer, size_t len) +{ + if (match_ServerHello(buffer, len) && state_packet_ServerHello.count++ < 3) { + drop("Server Hello"); + } else { + filter_run_next(fd, buffer, len); + } +} + +int match_ServerKeyExchange(const unsigned char* buffer, size_t len) +{ + return role == SERVER && len >= 13 + 1 && buffer[0] == 22 && buffer[13] == 12; +} + +void filter_packet_ServerKeyExchange(gnutls_transport_ptr_t fd, + const unsigned char* buffer, size_t len) +{ + if (match_ServerKeyExchange(buffer, len) && state_packet_ServerKeyExchange.count++ < 3) { + drop("Server Key Exchange"); + } else { + filter_run_next(fd, buffer, len); + } +} + +int match_ServerHelloDone(const unsigned char* buffer, size_t len) +{ + return role == SERVER && len >= 13 + 1 && buffer[0] == 22 && buffer[13] == 14; +} + +void filter_packet_ServerHelloDone(gnutls_transport_ptr_t fd, + const unsigned char* buffer, size_t len) +{ + if (match_ServerHelloDone(buffer, len) && state_packet_ServerHelloDone.count++ < 3) { + drop("Server Hello Done"); + } else { + filter_run_next(fd, buffer, len); + } +} + +int match_ClientKeyExchange(const unsigned char* buffer, size_t len) +{ + return role == CLIENT && len >= 13 + 1 && buffer[0] == 22 && buffer[13] == 16; +} + +void filter_packet_ClientKeyExchange(gnutls_transport_ptr_t fd, + const unsigned char* buffer, size_t len) +{ + if (match_ClientKeyExchange(buffer, len) && state_packet_ClientKeyExchange.count++ < 3) { + drop("Client Key Exchange"); + } else { + filter_run_next(fd, buffer, len); + } +} + +int match_ClientChangeCipherSpec(const unsigned char* buffer, size_t len) +{ + return role == CLIENT && len >= 13 && buffer[0] == 20; +} + +void filter_packet_ClientChangeCipherSpec(gnutls_transport_ptr_t fd, + const unsigned char* buffer, size_t len) +{ + if (match_ClientChangeCipherSpec(buffer, len) && state_packet_ClientChangeCipherSpec.count++ < 3) { + drop("Client Change Cipher Spec"); + } else { + filter_run_next(fd, buffer, len); + } +} + +int match_ClientFinished(const unsigned char* buffer, size_t len) +{ + return role == CLIENT && len >= 13 && buffer[0] == 22 && buffer[4] == 1; +} + +void filter_packet_ClientFinished(gnutls_transport_ptr_t fd, + const unsigned char* buffer, size_t len) +{ + if (match_ClientFinished(buffer, len) && state_packet_ClientFinished.count++ < 3) { + drop("Client Finished"); + } else { + filter_run_next(fd, buffer, len); + } +} + +int match_ServerChangeCipherSpec(const unsigned char* buffer, size_t len) +{ + return role == SERVER && len >= 13 && buffer[0] == 20; +} + +void filter_packet_ServerChangeCipherSpec(gnutls_transport_ptr_t fd, + const unsigned char* buffer, size_t len) +{ + if (match_ServerChangeCipherSpec(buffer, len) && state_packet_ServerChangeCipherSpec.count++ < 3) { + drop("Server Change Cipher Spec"); + } else { + filter_run_next(fd, buffer, len); + } +} + +int match_ServerFinished(const unsigned char* buffer, size_t len) +{ + return role == SERVER && len >= 13 && buffer[0] == 22 && buffer[4] == 1; +} + +void filter_packet_ServerFinished(gnutls_transport_ptr_t fd, + const unsigned char* buffer, size_t len) +{ + if (match_ServerFinished(buffer, len) && state_packet_ServerFinished.count++ < 3) { + drop("Server Finished"); + } else { + filter_run_next(fd, buffer, len); + } +} + + + +void filter_permutete_state_free_buffer(filter_permute_state_t* state) +{ + int i; + + for (i = 0; i < 3; i++) { + if (state->packets[i].data) { + free(state->packets[i].data); + } + } +} + +void filter_permute_state_run(filter_permute_state_t* state, int packetCount, + gnutls_transport_ptr_t fd, const unsigned char* buffer, size_t len) +{ + unsigned char* data = malloc(len); + int packet = state->order[state->count]; + + memcpy(data, buffer, len); + state->packets[packet].data = data; + state->packets[packet].size = len; + state->count++; + + if (state->count == packetCount) { + for (packet = 0; packet < packetCount; packet++) { + filter_run_next(fd, state->packets[packet].data, + state->packets[packet].size); + } + filter_permutete_state_free_buffer(state); + state->count = 0; + } +} + +void filter_permute_ServerHello(gnutls_transport_ptr_t fd, + const unsigned char* buffer, size_t len) +{ + if (match_ServerHello(buffer, len) + || match_ServerKeyExchange(buffer, len) + || match_ServerHelloDone(buffer, len)) { + filter_permute_state_run(&state_permute_ServerHello, 3, fd, buffer, len); + } else { + filter_run_next(fd, buffer, len); + } +} + +void filter_permute_ServerFinished(gnutls_transport_ptr_t fd, + const unsigned char* buffer, size_t len) +{ + if (match_ServerChangeCipherSpec(buffer, len) + || match_ServerFinished(buffer, len)) { + filter_permute_state_run(&state_permute_ServerFinished, 2, fd, buffer, len); + } else { + filter_run_next(fd, buffer, len); + } +} + +void filter_permute_ClientFinished(gnutls_transport_ptr_t fd, + const unsigned char* buffer, size_t len) +{ + if (match_ClientKeyExchange(buffer, len) + || match_ClientChangeCipherSpec(buffer, len) + || match_ClientFinished(buffer, len)) { + filter_permute_state_run(&state_permute_ClientFinished, 3, fd, buffer, len); + } else { + filter_run_next(fd, buffer, len); + } +} + + + + +ssize_t writefn(gnutls_transport_ptr_t fd, const void* buffer, size_t len) +{ + filter_current_idx = 0; + filter_run_next(fd, (const unsigned char*) buffer, len); + return len; +} + +void await(int fd) +{ + if (nonblock) { + struct pollfd p = { fd, POLLIN, 0 }; + poll(&p, 1, 100); + } +} + + + + +gnutls_session_t session(int sock, int server) +{ + gnutls_session_t r; + + gnutls_init(&r, GNUTLS_DATAGRAM | (server ? GNUTLS_SERVER : GNUTLS_CLIENT) + | GNUTLS_NONBLOCK * nonblock); + gnutls_priority_set_direct(r, "NORMAL:+ANON-ECDH", 0); + gnutls_transport_set_ptr(r, (gnutls_transport_ptr_t) (long long int) sock); + + if (server) { + gnutls_anon_server_credentials_t cred; + gnutls_anon_allocate_server_credentials(&cred); + gnutls_credentials_set(r, GNUTLS_CRD_ANON, cred); + } else { + gnutls_anon_client_credentials_t cred; + gnutls_anon_allocate_client_credentials(&cred); + gnutls_credentials_set(r, GNUTLS_CRD_ANON, cred); + } + + gnutls_transport_set_push_function(r, writefn); + + gnutls_dtls_set_mtu(r, 1400); + gnutls_dtls_set_timeouts(r, 1000, 60000); + + return r; +} + +int log_error(int code) +{ + if (code < 0 && code != GNUTLS_E_AGAIN) { + fprintf(stdout, "%i <%s tls> %s", run_id, role_to_name(role), gnutls_strerror(code)); + if (gnutls_error_is_fatal(code)) { + fprintf(stdout, " (fatal)\n"); + exit(1); + } else { + fprintf(stdout, "\n"); + } + } + return code; +} + +timer_t killtimer_tid; + +void reset_killtimer() +{ + if (nonblock) { + return; + } + struct itimerspec tout = { { 0, 0 }, { 120, 0 } }; + timer_settime(killtimer_tid, 0, &tout, 0); +} + +void setup_killtimer() +{ + struct sigevent sig; + + memset(&sig, 0, sizeof(sig)); + sig.sigev_notify = SIGEV_SIGNAL; + sig.sigev_signo = 15; + timer_create(CLOCK_MONOTONIC, &sig, &killtimer_tid); + + struct itimerspec tout = { { 0, 0 }, { 240, 0 } }; + timer_settime(killtimer_tid, 0, &tout, 0); +} + +void log_error_with_time(int err, time_t started) +{ + if (err < 0) { + if (err != GNUTLS_E_TIMEDOUT || (time(0) - started) >= 60) { + log_error(err); + } else { + fprintf(stdout, "{spurious}"); + log_error(err); + } + if (gnutls_error_is_fatal(err)) { + exit(1); + } + } +} + +void client(int sock) +{ + gnutls_session_t s = session(sock, 0); + int err = 0; + time_t started = time(0); + + setup_killtimer(); + + do { + await(sock); + err = log_error(gnutls_handshake(s)); + reset_killtimer(); + } while (err != 0 && !gnutls_error_is_fatal(err)); + log_error_with_time(err, started); + + started = time(0); + const char* line = "foobar!"; + do { + err = gnutls_record_send(s, line, strlen(line)); + reset_killtimer(); + } while (err < 0 && !gnutls_error_is_fatal(err)); + log_error_with_time(err, started); + + char buffer[8192]; + int len; + do { + await(sock); + len = gnutls_record_recv(s, buffer, sizeof(buffer)); + } while (len < 0 && !gnutls_error_is_fatal(len)); + if (len > 0 && strcmp(line, buffer) == 0) { + exit(0); + } else { + log_error(len); + exit(1); + } +} + +void server(int sock) +{ + gnutls_session_t s = session(sock, 1); + int err; + time_t started = time(0); + + write(sock, &sock, 1); + + setup_killtimer(); + + do { + await(sock); + err = log_error(gnutls_handshake(s)); + reset_killtimer(); + } while (err != 0 && !gnutls_error_is_fatal(err)); + log_error_with_time(err, started); + + for (;;) { + char buffer[8192]; + int len; + do { + await(sock); + len = gnutls_record_recv(s, buffer, sizeof(buffer)); + reset_killtimer(); + } while (len < 0 && !gnutls_error_is_fatal(len)); + log_error_with_time(len, started); + + gnutls_record_send(s, buffer, len); + exit(0); + } +} + +void udp_sockpair(int* socks) +{ + struct sockaddr_in6 sa = { AF_INET6, htons(30000), 0, in6addr_loopback, 0 }; + struct sockaddr_in6 sb = { AF_INET6, htons(20000), 0, in6addr_loopback, 0 }; + + socks[0] = socket(AF_INET6, SOCK_DGRAM, 0); + socks[1] = socket(AF_INET6, SOCK_DGRAM, 0); + + bind(socks[0], (struct sockaddr*) &sa, sizeof(sa)); + bind(socks[1], (struct sockaddr*) &sb, sizeof(sb)); + + connect(socks[1], (struct sockaddr*) &sa, sizeof(sa)); + connect(socks[0], (struct sockaddr*) &sb, sizeof(sb)); +} + +int run_test() +{ + int fds[2]; + int pid1, pid2; + int status2; + + socketpair(AF_LOCAL, SOCK_DGRAM, 0, fds); + + if (nonblock) { + fcntl(fds[0], F_SETFL, (long) O_NONBLOCK); + fcntl(fds[1], F_SETFL, (long) O_NONBLOCK); + } + + if (!(pid1 = fork())) { + setpgrp(); + role = SERVER; + server(fds[1]); + } + read(fds[0], &status2, sizeof(status2)); + if (!(pid2 = fork())) { + setpgrp(); + role = CLIENT; + client(fds[0]); + } + waitpid(pid2, &status2, 0); + kill(pid1, 15); + waitpid(pid1, 0, 0); + + close(fds[0]); + close(fds[1]); + + if (WIFEXITED(status2)) { + return !!WEXITSTATUS(status2); + } else { + return 2; + } +} + +static int permutations2[2][2] + = { { 0, 1 }, { 1, 0 } }; +static const char* permutations2names[2] + = { "01", "10" }; +static int permutations3[6][3] + = { { 0, 1, 2 }, { 0, 2, 1 }, + { 1, 0, 2 }, { 1, 2, 0 }, + { 2, 0, 1 }, { 2, 1, 0 } }; +static const char* permutations3names[6] + = { "012", "021", "102", "120", "201", "210" }; +static filter_fn filters[8] + = { filter_packet_ServerHello, + filter_packet_ServerKeyExchange, + filter_packet_ServerHelloDone, + filter_packet_ClientKeyExchange, + filter_packet_ClientChangeCipherSpec, + filter_packet_ClientFinished, + filter_packet_ServerChangeCipherSpec, + filter_packet_ServerFinished }; +static const char* filter_names[8] + = { "SHello", + "SKeyExchange", + "SHelloDone", + "CKeyExchange", + "CChangeCipherSpec", + "CFinished", + "SChangeCipherSpec", + "SFinished" }; + +int run_one_test(int dropMode, int serverFinishedPermute, int serverHelloPermute, int clientFinishedPermute) +{ + int fnIdx = 0; + run_id = ((dropMode * 2 + serverFinishedPermute) * 6 + serverHelloPermute) * 6 + clientFinishedPermute; + + filter_clear_state(); + + filter_chain[fnIdx++] = filter_permute_ServerHello; + state_permute_ServerHello.order = permutations3[serverHelloPermute]; + + filter_chain[fnIdx++] = filter_permute_ServerFinished; + state_permute_ServerFinished.order = permutations2[serverFinishedPermute]; + + filter_chain[fnIdx++] = filter_permute_ClientFinished; + state_permute_ClientFinished.order = permutations3[clientFinishedPermute]; + + if (dropMode) { + for (int filterIdx = 0; filterIdx < 8; filterIdx++) { + if (dropMode & (1 << filterIdx)) { + filter_chain[fnIdx++] = filters[filterIdx]; + } + } + } + filter_chain[fnIdx++] = NULL; + + int res = run_test(); + + switch (res) { + case 0: + fprintf(stdout, "%i ++ ", run_id); + break; + case 1: + fprintf(stdout, "%i -- ", run_id); + break; + case 2: + fprintf(stdout, "%i !! ", run_id); + break; + } + + fprintf(stdout, "SHello(%s), ", permutations3names[serverHelloPermute]); + fprintf(stdout, "SFinished(%s), ", permutations2names[serverFinishedPermute]); + fprintf(stdout, "CFinished(%s) :- ", permutations3names[clientFinishedPermute]); + if (dropMode) { + for (int filterIdx = 0; filterIdx < 8; filterIdx++) { + if (dropMode & (1 << filterIdx)) { + if (dropMode & ((1 << filterIdx) - 1)) { + fprintf(stdout, ", "); + } + fprintf(stdout, "%s", filter_names[filterIdx]); + } + } + } + fprintf(stdout, "\n"); + + if (res && debug) { + return 1; + } else { + return 0; + } +} + +void run_tests(int childcount) +{ + int children = 0; + + for (int dropMode = 0; dropMode != 1 << 8; dropMode++) + for (int serverFinishedPermute = 0; serverFinishedPermute < 2; serverFinishedPermute++) + for (int serverHelloPermute = 0; serverHelloPermute < 6; serverHelloPermute++) + for (int clientFinishedPermute = 0; clientFinishedPermute < 6; clientFinishedPermute++) { + if (!fork()) { + exit(run_one_test(dropMode, serverFinishedPermute, serverHelloPermute, clientFinishedPermute)); + } else { + children++; + while (children >= childcount) { + wait(0); + children--; + } + } + } + + while (children > 0) { + wait(0); + children--; + } +} + + + +int main(int argc, const char* argv[]) +{ + setlinebuf(stdout); + gnutls_global_init(); + gnutls_global_set_log_function(logfn); + gnutls_global_set_audit_log_function(auditfn); + + nonblock = 0; + debug = 0; + + if (argc == 1) { + run_tests(100); + } else { + int dropMode = 0; + int serverFinishedPermute = 0; + int serverHelloPermute = 0; + int clientFinishedPermute = 0; + + for (int arg = 1; arg < argc; arg++) { + if (strcmp("-shello", argv[arg]) == 0) { + arg++; + if (arg >= argc) { + fprintf(stderr, "No arg to -shello\n"); + exit(1); + } + while (serverHelloPermute < 6) { + if (strcmp(permutations3names[serverHelloPermute], argv[arg]) == 0) { + break; + } + serverHelloPermute++; + } + if (serverHelloPermute == 6) { + fprintf(stderr, "Unknown permutation %s\n", argv[arg]); + exit(1); + } + } else if (strcmp("-d", argv[arg]) == 0) { + debug++; + } else if (strcmp("-sfinished", argv[arg]) == 0) { + arg++; + if (arg >= argc) { + fprintf(stderr, "No arg to -sfinished\n"); + exit(1); + } + while (serverFinishedPermute < 2) { + if (strcmp(permutations2names[serverFinishedPermute], argv[arg]) == 0) { + break; + } + serverFinishedPermute++; + } + if (serverFinishedPermute == 2) { + fprintf(stderr, "Unknown permutation %s\n", argv[arg]); + exit(1); + } + } else if (strcmp("-cfinished", argv[arg]) == 0) { + arg++; + if (arg >= argc) { + fprintf(stderr, "No arg to -cfinished\n"); + exit(1); + } + while (clientFinishedPermute < 6) { + if (strcmp(permutations3names[clientFinishedPermute], argv[arg]) == 0) { + break; + } + clientFinishedPermute++; + } + if (clientFinishedPermute == 6) { + fprintf(stderr, "Unknown permutation %s\n", argv[arg]); + exit(1); + } + } else { + int drop; + for (drop = 0; drop < 8; drop++) { + if (strcmp(filter_names[drop], argv[arg]) == 0) { + dropMode |= (1 << drop); + break; + } + } + if (drop == 8) { + fprintf(stderr, "Unknown packet %s\n", argv[arg]); + exit(8); + } + } + } + + if (debug) + gnutls_global_set_log_level(99); + run_one_test(dropMode, serverFinishedPermute, serverHelloPermute, clientFinishedPermute); + } + + gnutls_global_deinit(); +} + -- cgit v1.2.1