This patch modifies the support/ab.c to handle SSL/TLS
properly.
The current implementation in 2.0.54 seems to be broken
because it dumps core when I compile it with "-DUSE_SSL".
Even when I go back to 2.0.39, it still has many problems.
i.e.
- Asynchronous I/O does not work with SSL, which means
only one slow connection prevents all other concurrent
connections from proceeding.
- It sleeps one second for each SSL connections during
SSL handshake.
- SIGSEGV occurs with "-v 4" because of the buffer
overflow inside ssl_print_cert_info().
- Cannot specify either protocol version or cipher suites.
This patch makes ab work with asynchronous I/O even in
SSL/TLS, while it introduces 2 more options for SSL/TLS.
-Z ciphersuite Specify SSL/TLS cipher suite (See openssl ciphers)
-f protocol Specify SSL/TLS protocol (SSL2, SSL3, TLS1, or ALL)
Example:
ab -f SSL3 -Z DES-CBC3-SHA -n 1000 -c 100 https://server/
This patch also includes the modification for configure.in
to set "-DAB_USE_SSL" automatically when you configure
apache with "--enable-ssl". You have to run buildconf
after applying this patch, of course.
--
Masaoki Kobayashi
<[EMAIL PROTECTED]>
diff -urN httpd-2.0.54/configure.in httpd-2.0.54-ab-ssl-patch/configure.in
--- httpd-2.0.54/configure.in 2005-03-30 20:00:06.000000000 +0900
+++ httpd-2.0.54-ab-ssl-patch/configure.in 2005-05-08 23:36:00.000000000
+0900
@@ -395,6 +395,10 @@
APACHE_SUBST(SHLIBPATH_VAR)
APACHE_SUBST(OS_SPECIFIC_VARS)
+if test "$enable_ssl" != "no"; then
+ APR_ADDTO(DEFS, "-DAB_USE_SSL")
+fi
+
PRE_SHARED_CMDS='echo ""'
POST_SHARED_CMDS='echo ""'
diff -urN httpd-2.0.54/support/ab.c httpd-2.0.54-ab-ssl-patch/support/ab.c
--- httpd-2.0.54/support/ab.c 2005-02-05 05:21:18.000000000 +0900
+++ httpd-2.0.54-ab-ssl-patch/support/ab.c 2005-05-08 23:36:00.000000000
+0900
@@ -91,7 +91,7 @@
* ab - or to due to a change in the distribution it is compiled with
* (such as an APR change in for example blocking).
*/
-#define AP_AB_BASEREVISION "2.0.41-dev"
+#define AP_AB_BASEREVISION "2.0.41-dev-ssl-patch"
/*
* BUGS:
@@ -144,7 +144,7 @@
#if APR_HAVE_STDLIB_H
#include <stdlib.h>
-#ifdef USE_SSL
+#ifdef AB_USE_SSL
#if ((!(RSAREF)) && (!(SYSSSL)))
/* Libraries on most systems.. */
#include <openssl/rsa.h>
@@ -154,6 +154,15 @@
#include <openssl/err.h>
#include <openssl/ssl.h>
#include <openssl/rand.h>
+#ifdef RSAREF
+ typedef STACK X509_STACK_TYPE;
+# define SK_NUM(x) sk_num(x)
+# define SK_VALUE(x,y) sk_value(x,y)
+#else
+ typedef STACK_OF(X509) X509_STACK_TYPE;
+# define SK_NUM(x) sk_X509_num(x)
+# define SK_VALUE(x,y) sk_X509_value(x,y)
+#endif
#else
/* Libraries for RSAref and SYSSSL */
#include <rsa.h>
@@ -214,15 +223,12 @@
done; /* Connection closed */
int socknum;
-#ifdef USE_SSL
+#ifdef AB_USE_SSL
SSL *ssl;
#endif
};
struct data {
-#ifdef USE_SSL
- /* XXXX insert SSL timings */
-#endif
int read; /* number of bytes read */
apr_time_t starttime; /* start time of connection in seconds since
* Jan. 1, 1970 */
@@ -288,10 +294,12 @@
long good = 0, bad = 0; /* number of good and bad requests */
long epipe = 0; /* number of broken pipe writes */
-#ifdef USE_SSL
-int ssl = 0;
-SSL_CTX *ctx;
-BIO *bio_out,*bio_err;
+#ifdef AB_USE_SSL
+int is_ssl;
+SSL_CTX *ssl_ctx;
+char *ssl_cipher = NULL;
+char *ssl_info = NULL;
+BIO *bio_out, *bio_err;
static void write_request(struct connection * c);
#endif
@@ -351,81 +359,13 @@
exit(rv);
}
-#if defined(USE_SSL) && USE_THREADS
-/*
- * To ensure thread-safetyness in OpenSSL - work in progress
- */
-
-static apr_thread_mutex_t **lock_cs;
-static int lock_num_locks;
-
-static void ssl_util_thr_lock(int mode, int type,
- const char *file, int line)
-{
- if (type < lock_num_locks) {
- if (mode & CRYPTO_LOCK) {
- apr_thread_mutex_lock(lock_cs[type]);
- }
- else {
- apr_thread_mutex_unlock(lock_cs[type]);
- }
- }
-}
-
-static unsigned long ssl_util_thr_id(void)
-{
- /* OpenSSL needs this to return an unsigned long. On OS/390, the pthread
- * id is a structure twice that big. Use the TCB pointer instead as a
- * unique unsigned long.
- */
-#ifdef __MVS__
- struct PSA {
- char unmapped[540];
- unsigned long PSATOLD;
- } *psaptr = 0;
-
- return psaptr->PSATOLD;
-#else
- return (unsigned long) apr_os_thread_current();
-#endif
-}
-
-static apr_status_t ssl_util_thread_cleanup(void *data)
-{
- CRYPTO_set_locking_callback(NULL);
-
- /* Let the registered mutex cleanups do their own thing
- */
- return APR_SUCCESS;
-}
-
-void ssl_util_thread_setup(apr_pool_t *p)
-{
- int i;
-
- lock_num_locks = CRYPTO_num_locks();
- lock_cs = apr_palloc(p, lock_num_locks * sizeof(*lock_cs));
-
- for (i = 0; i < lock_num_locks; i++) {
- apr_thread_mutex_create(&(lock_cs[i]), APR_THREAD_MUTEX_DEFAULT, p);
- }
-
- CRYPTO_set_id_callback(ssl_util_thr_id);
-
- CRYPTO_set_locking_callback(ssl_util_thr_lock);
-
- apr_pool_cleanup_register(p, NULL, ssl_util_thread_cleanup,
- apr_pool_cleanup_null);
-}
-#endif
-
/* --------------------------------------------------------- */
/* write out request to a connection - assumes we can write
* (small) request out in one go into our new socket buffer
*
*/
-#ifdef USE_SSL
-long ssl_print_cb(BIO *bio,int cmd,const char *argp,int argi,long argl,long
ret)
+#ifdef AB_USE_SSL
+static long ssl_print_cb(BIO *bio, int cmd, const char *argp, int argi, long
argl, long ret)
{
BIO *out;
@@ -434,20 +374,38 @@
if (cmd == (BIO_CB_READ|BIO_CB_RETURN))
{
- BIO_printf(out,"read from %08X [%08lX] (%d bytes => %ld (0x%X))\n",
- bio,argp,argi,ret,ret);
- BIO_dump(out,(char *)argp,(int)ret);
+ BIO_printf(out, "read from %08X [%08lX] (%d bytes => %ld (0x%X))\n",
+ bio, argp, argi, ret, ret);
+ BIO_dump(out, (char *)argp, (int)ret);
return(ret);
}
else if (cmd == (BIO_CB_WRITE|BIO_CB_RETURN))
{
- BIO_printf(out,"write to %08X [%08lX] (%d bytes => %ld (0x%X))\n",
- bio,argp,argi,ret,ret);
- BIO_dump(out,(char *)argp,(int)ret);
+ BIO_printf(out, "write to %08X [%08lX] (%d bytes => %ld (0x%X))\n",
+ bio, argp, argi, ret, ret);
+ BIO_dump(out, (char *)argp, (int)ret);
}
return(ret);
}
+static void ssl_state_cb(const SSL *s, int w, int r)
+{
+ if (w & SSL_CB_ALERT) {
+ BIO_printf(bio_err, "SSL/TLS Alert [%s] %s:%s\n",
+ (w & SSL_CB_READ ? "read" : "write"),
+ SSL_alert_type_string_long(r),
+ SSL_alert_desc_string_long(r));
+ } else if (w & SSL_CB_LOOP) {
+ BIO_printf(bio_err, "SSL/TLS State [%s] %s\n",
+ (SSL_in_connect_init(s) ? "connect" : "-"),
+ SSL_state_string_long(s));
+ } else if (w & (SSL_CB_HANDSHAKE_START|SSL_CB_HANDSHAKE_DONE)) {
+ BIO_printf(bio_err, "SSL/TLS Handshake [%s] %s\n",
+ (w & SSL_CB_HANDSHAKE_START ? "Start" : "Done"),
+ SSL_state_string_long(s));
+ }
+}
+
#ifndef RAND_MAX
#include <limits.h>
#define RAND_MAX INT_MAX
@@ -499,14 +457,12 @@
nDone += 128;
}
-int ssl_print_connection_info(bio,ssl)
-BIO *bio;
-SSL *ssl;
+int ssl_print_connection_info(BIO *bio, SSL *ssl)
{
SSL_CIPHER *c;
int alg_bits,bits;
- c=SSL_get_current_cipher(ssl);
+ c = SSL_get_current_cipher(ssl);
BIO_printf(bio,"Cipher Suite Protocol :%s\n",
SSL_CIPHER_get_version(c));
BIO_printf(bio,"Cipher Suite Name :%s\n",SSL_CIPHER_get_name(c));
@@ -516,170 +472,125 @@
return(1);
}
-int ssl_print_cert_info(bio,x509cert)
-BIO *bio;
-X509 *x509cert;
+void ssl_print_cert_info(BIO *bio, X509 *cert)
{
X509_NAME *dn;
- char buf[64];
+ char buf[1024];
- BIO_printf(bio,"Certificate version:
%d\n",X509_get_version(x509cert)+1);
+ BIO_printf(bio, "Certificate version: %d\n", X509_get_version(cert)+1);
BIO_printf(bio,"Valid from: ");
- ASN1_UTCTIME_print(bio, X509_get_notBefore(x509cert));
+ ASN1_UTCTIME_print(bio, X509_get_notBefore(cert));
BIO_printf(bio,"\n");
BIO_printf(bio,"Valid to : ");
- ASN1_UTCTIME_print(bio, X509_get_notAfter(x509cert));
+ ASN1_UTCTIME_print(bio, X509_get_notAfter(cert));
BIO_printf(bio,"\n");
BIO_printf(bio,"Public key is %d bits\n",
- EVP_PKEY_bits(X509_get_pubkey(x509cert)));
+ EVP_PKEY_bits(X509_get_pubkey(cert)));
- dn=X509_get_issuer_name(x509cert);
- X509_NAME_oneline(dn, buf, BUFSIZ);
- BIO_printf(bio,"The issuer name is %s\n", buf);
-
- dn=X509_get_subject_name(x509cert);
- X509_NAME_oneline(dn, buf, BUFSIZ);
- BIO_printf(bio,"The subject name is %s\n", buf);
+ dn = X509_get_issuer_name(cert);
+ X509_NAME_oneline(dn, buf, sizeof(buf));
+ BIO_printf(bio, "The issuer name is %s\n", buf);
+
+ dn=X509_get_subject_name(cert);
+ X509_NAME_oneline(dn, buf, sizeof(buf));
+ BIO_printf(bio, "The subject name is %s\n", buf);
/* dump the extension list too */
- BIO_printf(bio,"Extension Count: %d\n",X509_get_ext_count(x509cert));
-
- return(1);
+ BIO_printf(bio, "Extension Count: %d\n", X509_get_ext_count(cert));
}
-void ssl_start_connect(struct connection * c)
+void ssl_print_info(struct connection *c)
{
- BIO *bio;
- X509 *x509cert;
-#ifdef RSAREF
- STACK *sk;
-#else
- STACK_OF(X509) *sk;
-#endif
- int i, count, hdone = 0;
- char ssl_hostname[80];
-
- /* XXX - Verify if it's okay - TBD */
- if (requests < concurrency)
- requests = concurrency;
-
- if (!(started < requests))
- return;
-
- c->read = 0;
- c->bread = 0;
- c->keepalive = 0;
- c->cbx = 0;
- c->gotheader = 0;
- c->rwrite = 0;
- if (c->ctx)
- apr_pool_destroy(c->ctx);
- apr_pool_create(&c->ctx, cntxt);
-
- if ((c->ssl=SSL_new(ctx)) == NULL)
- {
- BIO_printf(bio_err,"SSL_new failed\n");
- exit(1);
- }
-
- ssl_rand_seed();
-
- c->start = apr_time_now();
- memset(ssl_hostname, 0, 80);
- sprintf(ssl_hostname, "%s:%d", hostname, port);
-
- if ((bio = BIO_new_connect(ssl_hostname)) == NULL)
- {
- BIO_printf(bio_err,"BIO_new_connect failed\n");
- exit(1);
- }
- SSL_set_bio(c->ssl,bio,bio);
- SSL_set_connect_state(c->ssl);
-
- if (verbosity >= 4)
- {
- BIO_set_callback(bio,ssl_print_cb);
- BIO_set_callback_arg(bio,(void*)bio_err);
- }
-
- while (!hdone)
- {
- i = SSL_do_handshake(c->ssl);
-
- switch (SSL_get_error(c->ssl,i))
- {
- case SSL_ERROR_NONE:
- hdone=1;
- break;
- case SSL_ERROR_SSL:
- case SSL_ERROR_SYSCALL:
- BIO_printf(bio_err,"SSL connection failed\n");
- err_conn++;
- c->state = STATE_UNCONNECTED;
- if (bad++ > 10) {
- SSL_free (c->ssl);
- BIO_printf(bio_err,"\nTest aborted after 10 failures\n\n");
- exit (1);
- }
- break;
- case SSL_ERROR_WANT_READ:
- case SSL_ERROR_WANT_WRITE:
- case SSL_ERROR_WANT_CONNECT:
- BIO_printf(bio_err, "Waiting .. sleep(1)\n");
- apr_sleep(apr_time_from_sec(1));
- c->state = STATE_CONNECTED;
- c->rwrite = 0;
- break;
- case SSL_ERROR_ZERO_RETURN:
- BIO_printf(bio_err,"socket closed\n");
- break;
- }
- }
-
- if (verbosity >= 2)
- {
- BIO_printf(bio_err, "\n");
- sk = SSL_get_peer_cert_chain(c->ssl);
-#ifdef RSAREF
- if ((count = sk_num(sk)) > 0)
-#else
- if ((count = sk_X509_num(sk)) > 0)
-#endif
- {
- for (i=1; i<count; i++)
- {
-#ifdef RSAREF
- x509cert = (X509 *)sk_value(sk,i);
-#else
- x509cert = (X509 *)sk_X509_value(sk,i);
-#endif
- ssl_print_cert_info(bio_out,x509cert);
- X509_free(x509cert);
- }
- }
-
- x509cert = SSL_get_peer_certificate(c->ssl);
- if (x509cert == NULL)
- BIO_printf(bio_out, "Anon DH\n");
- else
- {
- BIO_printf(bio_out, "Peer certificate\n");
- ssl_print_cert_info(bio_out,x509cert);
- X509_free(x509cert);
- }
+ X509_STACK_TYPE *sk;
+ X509 *cert;
+ int count;
+
+ BIO_printf(bio_err, "\n");
+ sk = SSL_get_peer_cert_chain(c->ssl);
+ if ((count = SK_NUM(sk)) > 0) {
+ int i;
+ for (i=1; i<count; i++) {
+ cert = (X509 *)SK_VALUE(sk, i);
+ ssl_print_cert_info(bio_out, cert);
+ X509_free(cert);
+ }
+ }
+ cert = SSL_get_peer_certificate(c->ssl);
+ if (cert == NULL) {
+ BIO_printf(bio_out, "Anon DH\n");
+ } else {
+ BIO_printf(bio_out, "Peer certificate\n");
+ ssl_print_cert_info(bio_out, cert);
+ X509_free(cert);
+ }
+ ssl_print_connection_info(bio_err,c->ssl);
+ SSL_SESSION_print(bio_err, SSL_get_session(c->ssl));
+}
+
+void ssl_proceed_handshake(struct connection *c)
+{
+ int do_next = 1;
+
+ while(do_next) {
+ int ret, ecode;
+ apr_pollfd_t new_pollfd;
+
+ ret = SSL_do_handshake(c->ssl);
+ ecode = SSL_get_error(c->ssl, ret);
+
+ switch(ecode) {
+ case SSL_ERROR_NONE:
+ if (verbosity >= 2)
+ ssl_print_info(c);
+ if (ssl_info == NULL) {
+ SSL_CIPHER *ci;
+ X509 *cert;
+ int sk_bits, pk_bits;
+
+ ci = SSL_get_current_cipher(c->ssl);
+ SSL_CIPHER_get_bits(ci, &sk_bits);
+ cert = SSL_get_peer_certificate(c->ssl);
+ if (cert)
+ pk_bits = EVP_PKEY_bits(X509_get_pubkey(cert));
+ else
+ pk_bits = 0; /* Anon DH */
- ssl_print_connection_info(bio_err,c->ssl);
- SSL_SESSION_print(bio_err,SSL_get_session(c->ssl));
+ ssl_info = malloc(128);
+ apr_snprintf(ssl_info, 128, "%s,%s,%d,%d",
+ SSL_CIPHER_get_version(ci),
+ SSL_CIPHER_get_name(ci),
+ pk_bits, sk_bits);
+ }
+ write_request(c);
+ do_next = 0;
+ break;
+ case SSL_ERROR_WANT_READ:
+ new_pollfd.desc_type = APR_POLL_SOCKET;
+ new_pollfd.reqevents = APR_POLLIN;
+ new_pollfd.desc.s = c->aprsock;
+ new_pollfd.client_data = c;
+ apr_pollset_add(readbits, &new_pollfd);
+ do_next = 0;
+ break;
+ case SSL_ERROR_WANT_WRITE:
+ /* Try again */
+ do_next = 1;
+ break;
+ case SSL_ERROR_WANT_CONNECT:
+ case SSL_ERROR_SSL:
+ case SSL_ERROR_SYSCALL:
+ /* Unexpected result */
+ BIO_printf(bio_err, "SSL handshake failed (%d).\n", ecode);
+ ERR_print_errors(bio_err);
+ close_connection(c);
+ break;
+ }
}
-
- /* connected first time */
- started++;
- write_request(c);
}
-#endif /* USE_SSL */
+#endif /* AB_USE_SSL */
static void write_request(struct connection * c)
{
@@ -692,9 +603,6 @@
* First time round ?
*/
if (c->rwrite == 0) {
-#ifdef USE_SSL
- if (ssl != 1)
-#endif
apr_socket_timeout_set(c->aprsock, 0);
c->connect = tnow;
c->rwrite = reqlen;
@@ -708,19 +616,19 @@
return;
}
-#ifdef USE_SSL
- if (ssl == 1) {
+#ifdef AB_USE_SSL
+ if (c->ssl) {
apr_size_t e_ssl;
- e_ssl = SSL_write(c->ssl,request + c->rwrote, l);
- if (e_ssl != l)
- {
+ e_ssl = SSL_write(c->ssl, request + c->rwrote, l);
+ if (e_ssl != l) {
printf("SSL write failed - closing connection\n");
+ ERR_print_errors(bio_err);
close_connection (c);
return;
}
l = e_ssl;
- }
- else
+ e = APR_SUCCESS;
+ } else
#endif
e = apr_send(c->aprsock, request + c->rwrote, &l);
@@ -730,9 +638,6 @@
if (l == c->rwrite)
break;
-#ifdef USE_SSL
- if (ssl != 1)
-#endif
if (e != APR_SUCCESS) {
/*
* Let's hope this traps EWOULDBLOCK too !
@@ -751,9 +656,6 @@
totalposted += c->rwrite;
c->state = STATE_READ;
c->endwrite = apr_time_now();
-#ifdef USE_SSL
- if (ssl != 1)
-#endif
{
apr_pollfd_t new_pollfd;
new_pollfd.desc_type = APR_POLL_SOCKET;
@@ -820,6 +722,10 @@
printf("Server Software: %s\n", servername);
printf("Server Hostname: %s\n", hostname);
printf("Server Port: %hd\n", port);
+#ifdef AB_USE_SSL
+ if (is_ssl)
+ printf("SSL/TLS Protocol: %s\n", ssl_info);
+#endif
printf("\n");
printf("Document Path: %s\n", path);
printf("Document Length: %" APR_SIZE_T_FMT " bytes\n", doclen);
@@ -1184,13 +1090,6 @@
{
apr_status_t rv;
-#ifdef USE_SSL
- if (ssl == 1) {
- ssl_start_connect(c);
- return;
- }
-#endif
-
if (!(started < requests))
return;
@@ -1213,6 +1112,28 @@
apr_err("socket nonblock", rv);
}
c->start = apr_time_now();
+#ifdef AB_USE_SSL
+ if (is_ssl) {
+ BIO *bio;
+ apr_os_sock_t fd;
+ if ((c->ssl = SSL_new(ssl_ctx)) == NULL) {
+ BIO_printf(bio_err, "SSL_new failed.\n");
+ ERR_print_errors(bio_err);
+ exit(1);
+ }
+ ssl_rand_seed();
+ apr_os_sock_get(&fd, c->aprsock);
+ bio = BIO_new_socket(fd, BIO_NOCLOSE);
+ SSL_set_bio(c->ssl, bio, bio);
+ SSL_set_connect_state(c->ssl);
+ if (verbosity >= 4) {
+ BIO_set_callback(bio, ssl_print_cb);
+ BIO_set_callback_arg(bio, bio_err);
+ }
+ } else {
+ c->ssl = NULL;
+ }
+#endif
if ((rv = apr_connect(c->aprsock, destsa)) != APR_SUCCESS) {
if (APR_STATUS_IS_EINPROGRESS(rv)) {
apr_pollfd_t new_pollfd;
@@ -1246,6 +1167,11 @@
/* connected first time */
c->state = STATE_CONNECTED;
started++;
+#ifdef AB_USE_SSL
+ if (c->ssl)
+ ssl_proceed_handshake(c);
+ else
+#endif
write_request(c);
}
@@ -1288,18 +1214,18 @@
}
}
-#ifdef USE_SSL
- if (ssl == 1) {
- SSL_shutdown(c->ssl);
- SSL_free(c->ssl);
- }
- else
-#endif
{
apr_pollfd_t remove_pollfd;
remove_pollfd.desc_type = APR_POLL_SOCKET;
remove_pollfd.desc.s = c->aprsock;
apr_pollset_remove(readbits, &remove_pollfd);
+#ifdef AB_USE_SSL
+ if (c->ssl) {
+ SSL_shutdown(c->ssl);
+ SSL_free(c->ssl);
+ c->ssl = NULL;
+ }
+#endif
apr_socket_close(c->aprsock);
}
c->state = STATE_UNCONNECTED;
@@ -1321,17 +1247,17 @@
char respcode[4]; /* 3 digits and null */
r = sizeof(buffer);
-#ifdef USE_SSL
- if (ssl == 1)
- {
+#ifdef AB_USE_SSL
+ if (c->ssl) {
status = SSL_read (c->ssl, buffer, r);
if (status <= 0) {
good++; c->read = 0;
if (status < 0) printf("SSL read failed - closing connection\n");
+ ERR_print_errors(bio_err);
close_connection(c);
return;
}
- r = status;
+ r = status;
}
else {
#endif
@@ -1350,7 +1276,7 @@
* certain number of them before completely failing? -aaron */
apr_err("apr_recv", status);
}
-#ifdef USE_SSL
+#ifdef AB_USE_SSL
}
#endif
@@ -1622,9 +1548,6 @@
#endif /* NOT_ASCII */
/* This only needs to be done once */
-#ifdef USE_SSL
- if (ssl != 1)
-#endif
if ((rv = apr_sockaddr_info_get(&destsa, connecthost, APR_UNSPEC,
connectport, 0, cntxt))
!= APR_SUCCESS) {
char buf[120];
@@ -1656,11 +1579,6 @@
}
n = concurrency;
-#ifdef USE_SSL
- if (ssl == 1)
- status = APR_SUCCESS;
- else
-#endif
status = apr_pollset_poll(readbits, aprtimeout, &n, &pollresults);
if (status != APR_SUCCESS)
apr_err("apr_poll", status);
@@ -1676,16 +1594,18 @@
/*
* If the connection isn't connected how can we check it?
*/
- if (c->state == STATE_UNCONNECTED)
+ if (c->state == STATE_UNCONNECTED) {
continue;
+ }
-#ifdef USE_SSL
- if (ssl == 1)
- rv = APR_POLLIN;
- else
-#endif
rv = next_fd->rtnevents;
+#ifdef AB_USE_SSL
+ if (c->state == STATE_CONNECTED && c->ssl && SSL_in_init(c->ssl)) {
+ ssl_proceed_handshake(c);
+ continue;
+ }
+#endif
/*
* Notes: APR_POLLHUP is set after FIN is received on some
* systems, so treat that like APR_POLLIN so that we try to read
@@ -1727,6 +1647,11 @@
}
else {
c->state = STATE_CONNECTED;
+#ifdef AB_USE_SSL
+ if (c->ssl)
+ ssl_proceed_handshake(c);
+ else
+#endif
write_request(c);
}
}
@@ -1742,17 +1667,14 @@
* connection is in STATE_READ or STATE_CONNECTING we'll add the
* socket back in as APR_POLLIN.
*/
-#ifdef USE_SSL
- if (ssl != 1)
-#endif
- if (c->state == STATE_READ) {
- apr_pollfd_t new_pollfd;
- new_pollfd.desc_type = APR_POLL_SOCKET;
- new_pollfd.reqevents = APR_POLLIN;
- new_pollfd.desc.s = c->aprsock;
- new_pollfd.client_data = c;
- apr_pollset_add(readbits, &new_pollfd);
- }
+ if (c->state == STATE_READ) {
+ apr_pollfd_t new_pollfd;
+ new_pollfd.desc_type = APR_POLL_SOCKET;
+ new_pollfd.reqevents = APR_POLLIN;
+ new_pollfd.desc.s = c->aprsock;
+ new_pollfd.client_data = c;
+ apr_pollset_add(readbits, &new_pollfd);
+ }
}
}
@@ -1791,7 +1713,7 @@
static void usage(const char *progname)
{
fprintf(stderr, "Usage: %s [options] [http"
-#ifdef USE_SSL
+#ifdef AB_USE_SSL
"[s]"
#endif
"://]hostname[:port]/path\n", progname);
@@ -1821,10 +1743,11 @@
fprintf(stderr, " -S Do not show confidence estimators and
warnings.\n");
fprintf(stderr, " -g filename Output collected data to gnuplot
format file.\n");
fprintf(stderr, " -e filename Output CSV file with percentages
served\n");
-#ifdef USE_SSL
- fprintf(stderr, " -s Use httpS instead of HTTP (SSL)\n");
-#endif
fprintf(stderr, " -h Display usage information (this
message)\n");
+#ifdef AB_USE_SSL
+ fprintf(stderr, " -Z ciphersuite Specify SSL/TLS cipher suite (See
openssl ciphers)\n");
+ fprintf(stderr, " -f protocol Specify SSL/TLS protocol (SSL2, SSL3,
TLS1, or ALL)\n");
+#endif
exit(EINVAL);
}
@@ -1844,22 +1767,20 @@
if (strlen(url) > 7 && strncmp(url, "http://", 7) == 0) {
url += 7;
-#ifdef USE_SSL
- ssl = 0;
+#ifdef AB_USE_SSL
+ is_ssl = 0;
#endif
}
else
-#ifdef USE_SSL
if (strlen(url) > 8 && strncmp(url, "https://", 8) == 0) {
+#ifdef AB_USE_SSL
url += 8;
- ssl = 1;
- }
+ is_ssl = 1;
#else
- if (strlen(url) > 8 && strncmp(url, "https://", 8) == 0) {
fprintf(stderr, "SSL not compiled in; no https support\n");
exit(1);
- }
#endif
+ }
if ((cp = strchr(url, '/')) == NULL)
return 1;
@@ -1880,8 +1801,8 @@
}
if (port == 0) { /* no port specified */
-#ifdef USE_SSL
- if (ssl == 1)
+#ifdef AB_USE_SSL
+ if (is_ssl)
port = 443;
else
#endif
@@ -1889,8 +1810,8 @@
}
if ((
-#ifdef USE_SSL
- (ssl == 1) && (port != 443)) || (( ssl == 0 ) &&
+#ifdef AB_USE_SSL
+ is_ssl && (port != 443)) || (!is_ssl &&
#endif
(port != 80)))
{
@@ -1955,6 +1876,9 @@
apr_getopt_t *opt;
const char *optarg;
char c;
+#ifdef AB_USE_SSL
+ SSL_METHOD *meth = SSLv23_client_method();
+#endif
/* table defaults */
tablestring = "";
@@ -1989,19 +1913,11 @@
apr_getopt_init(&opt, cntxt, argc, argv);
while ((status = apr_getopt(opt, "n:c:t:T:p:v:kVhwix:y:z:C:H:P:A:g:X:de:Sq"
-#ifdef USE_SSL
- "s"
+#ifdef AB_USE_SSL
+ "Z:f:"
#endif
,&c, &optarg)) == APR_SUCCESS) {
switch (c) {
- case 's':
-#ifdef USE_SSL
- ssl = 1;
- break;
-#else
- fprintf(stderr, "SSL not compiled in; no https support\n");
- exit(1);
-#endif
case 'n':
requests = atoi(optarg);
if (!requests) {
@@ -2133,6 +2049,22 @@
case 'V':
copyright();
return 0;
+#ifdef AB_USE_SSL
+ case 'Z':
+ ssl_cipher = strdup(optarg);
+ break;
+ case 'f':
+ if (strncasecmp(optarg, "ALL", 3) == 0) {
+ meth = SSLv23_client_method();
+ } else if (strncasecmp(optarg, "SSL2", 4) == 0) {
+ meth = SSLv2_client_method();
+ } else if (strncasecmp(optarg, "SSL3", 4) == 0) {
+ meth = SSLv3_client_method();
+ } else if (strncasecmp(optarg, "TLS1", 4) == 0) {
+ meth = TLSv1_client_method();
+ }
+ break;
+#endif
}
}
@@ -2161,7 +2093,7 @@
else
heartbeatres = 0;
-#ifdef USE_SSL
+#ifdef AB_USE_SSL
#ifdef RSAREF
R_malloc_init();
#else
@@ -2169,19 +2101,25 @@
#endif
SSL_load_error_strings();
SSL_library_init();
- bio_out=BIO_new_fp(stdout,BIO_NOCLOSE);
- bio_err=BIO_new_fp(stderr,BIO_NOCLOSE);
+ bio_out = BIO_new_fp(stdout, BIO_NOCLOSE);
+ bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
- /* TODO: Allow force SSLv2_client_method() (TLSv1?) */
- if (!(ctx = SSL_CTX_new(SSLv23_client_method()))) {
- fprintf(stderr, "Could not init SSL CTX");
+ if (!(ssl_ctx = SSL_CTX_new(meth))) {
+ fprintf(stderr, "Could not initialize an SSL context.\n");
ERR_print_errors_fp(stderr);
exit(1);
}
- SSL_CTX_set_options(ctx, SSL_OP_ALL);
-#ifdef USE_THREADS
- ssl_util_thread_setup(cntxt);
-#endif
+ SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL);
+ if (ssl_cipher != NULL) {
+ if (!SSL_CTX_set_cipher_list(ssl_ctx, ssl_cipher)) {
+ fprintf(stderr, "error setting cipher list [%s]\n", ssl_cipher);
+ ERR_print_errors_fp(stderr);
+ exit(1);
+ }
+ }
+ if (verbosity >= 3) {
+ SSL_CTX_set_info_callback(ssl_ctx, ssl_state_cb);
+ }
#endif
#ifdef SIGPIPE
apr_signal(SIGPIPE, SIG_IGN); /* Ignore writes to connections that