1 /* distcache, Distributed Session Caching technology 2 * Copyright (C) 2000-2003 Geoff Thorpe, and Cryptographic Appliances, Inc. 3 * Copyright (C) 2004 The Distcache.org project 4 * 5 * This library is free software; you can redistribute it and/or modify it under 6 * the terms of the GNU Lesser General Public License as published by the Free 7 * Software Foundation; using version 2.1 of the License. The copyright holders 8 * may elect to allow the application of later versions of the License to this 9 * software, please contact the author (geoff@distcache.org) if you wish us to 10 * review any later version released by the Free Software Foundation. 11 * 12 * This library is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 14 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 15 * details. 16 * 17 * You should have received a copy of the GNU Lesser General Public License 18 * along with this library; if not, write to the Free Software Foundation, Inc., 19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 */ 21 #ifndef HEADER_SWAMP_H 22 #define HEADER_SWAMP_H 23 24 /* We must declare our purpose to libsys */ 25 #define SYS_GENERATING_EXE 26 27 #include <libsys/pre.h> 28 #include <libnal/nal.h> 29 30 /* Source OpenSSL */ 31 #include <openssl/ssl.h> 32 #include <openssl/err.h> 33 #include <openssl/rand.h> 34 #ifdef HAVE_ENGINE 35 #include <openssl/engine.h> 36 #endif 37 38 #include <libsys/post.h> 39 40 /*********************************************************/ 41 /* types and defines implemented/used in; swamp.c */ 42 /*********************************************************/ 43 44 /* Predeclarations */ 45 typedef struct st_swamp_thread_ctx swamp_thread_ctx; 46 typedef struct st_server_iterator server_iterator; 47 typedef struct st_swamp_config swamp_config; 48 typedef struct st_dist_pattern dist_pattern; 49 50 /* An individual "swamp_item". Each one of these cycles through the loop of 51 * connecting to a server, performing the SSL/TLS handshake, sending a request, 52 * reading a response, and closing the connection. */ 53 typedef struct st_swamp_item { 54 /* The parent "thread_ctx" that owns us */ 55 const swamp_thread_ctx *parent; 56 /********************************************************/ 57 /* The SSL/TLS, http(s), request/response "state" stuff */ 58 /********************************************************/ 59 SSL *ssl; 60 /* Last used session, for resumes. */ 61 SSL_SESSION *ssl_sess; 62 /* The BIOs hooked into the 'dirty' side of 'ssl'. */ 63 BIO *bio_in; 64 BIO *bio_out; 65 /* A buffer for the clear-text request we're sending */ 66 const unsigned char *request; 67 unsigned int request_size; 68 unsigned int request_sent; 69 /* A buffer for the clear-text response we're reading */ 70 unsigned char *response; 71 unsigned int response_size; 72 unsigned int response_received; 73 unsigned int response_expected; 74 /********************************/ 75 /* The connection to the server */ 76 /********************************/ 77 NAL_CONNECTION *conn; 78 /***************************************/ 79 /* The iterator across the server list */ 80 /***************************************/ 81 server_iterator *server_iterator; 82 /*********/ 83 /* Stats */ 84 /*********/ 85 unsigned int total_completed; 86 unsigned int total_failed; 87 unsigned int handshake_complete; 88 unsigned int resumes_hit; 89 unsigned int resumes_missed; 90 } swamp_item; 91 92 /* A context for managing multiple "swamp_item"s in a single-thread 93 * single-process async-I/O manner. */ 94 struct st_swamp_thread_ctx { 95 /* The configuration we work from */ 96 const swamp_config *config; 97 /* SSL_CTX containing our settings and OpenSSL state */ 98 SSL_CTX *ssl_ctx; 99 /* The list of swamp items */ 100 swamp_item *items; 101 unsigned int size; 102 /* The selector used for async-I/O */ 103 NAL_SELECTOR *sel; 104 /* Collected stats from across all swamp items */ 105 unsigned int total_completed; 106 unsigned int total_failed; 107 unsigned int total_max; 108 unsigned int resumes_hit; 109 unsigned int resumes_missed; 110 }; 111 112 /*********************************************************/ 113 /* types and defines implemented/used in; text_msg.c */ 114 /*********************************************************/ 115 116 void copyright(int nologo); 117 void main_usage(void); 118 int unknown_switch(const char *str); 119 void verify_result_warning(void); 120 int openssl_err(void); 121 122 /*********************************************************/ 123 /* types and defines implemented/used in; utils.c */ 124 /*********************************************************/ 125 126 /* tokeniser code */ 127 128 typedef struct { 129 const char *string; 130 const char *delimiters; 131 const char *position; 132 char *token; 133 } tokeniser_t; 134 int init_tokeniser(tokeniser_t *t, const char *string, const char *delimiters); 135 void free_tokeniser(tokeniser_t *t); 136 char *do_tokenising(tokeniser_t *t); 137 138 /* Common library wrapper functions */ 139 140 /* Wrap strtol so we (a) get error handling automatically, (b) don't have to * 141 * specify a base, and (c) could build easily on platforms without strol(). */ 142 int int_strtol(const char *str, long *val); 143 /* Wrap strtoul in the same way, except we also return failure if the number 144 * parsed was in fact negative. */ 145 int int_strtoul(const char *str, unsigned long *val); 146 147 /* Substring variants. These work the same as the above except it is not assumed 148 * the string up to the NULL-terminator must be entirely numeric, parsing can 149 * terminate on any non-numeric character, if valid_terms is NULL *or* on the 150 * first character from the valid_terms string. If valid_terms is non-NULL and 151 * parsing encounters a non-numeric character not in valid_terms, the result is 152 * failure. */ 153 int int_substrtol(const char *str, long *val, const char *valid_terms); 154 int int_substrtoul(const char *str, unsigned long *val, const char *valid_terms); 155 156 /* Parsing and manipulation tools */ 157 158 /* Take a string input and return a copy with all "un-escaping" performed. Ie. 159 * the literal string "hello\nI am fine\n" is converted to a string with two 160 * line-feed control-characters. */ 161 char *util_parse_escaped_string(const char *str_toconvert); 162 163 typedef enum st_swamp_sslmeth { 164 SWAMP_SSLMETH_NORMAL, /* SSLv23_client_method() */ 165 #if OPENSSL_VERSION_NUMBER < 0x10100000L && !defined(OPENSSL_NO_SSL2) 166 SWAMP_SSLMETH_SSLv2, /* SSLv2_client_method() */ 167 #endif 168 #ifndef OPENSSL_NO_SSL3_METHOD 169 SWAMP_SSLMETH_SSLv3, /* SSLv3_client_method() */ 170 #endif 171 SWAMP_SSLMETH_TLSv1 /* TLSv1_client_method() */ 172 } swamp_sslmeth; 173 174 /* Take a string input and map it to one of the SSLMETH types. */ 175 int util_parse_sslmeth(const char *str_toconvert, swamp_sslmeth *val); 176 177 /*********************************************************/ 178 /* types and defines implemented/used in; swamp_conf.c */ 179 /*********************************************************/ 180 181 /* If DATE_OUTPUT is defined, the date/time the testing begins is output before 182 * the tests start and likewise the date/time of the completion is output last. 183 * Useful when many simultaneous instances are being run and the output is being 184 * piped to files. */ 185 /* #define DATE_OUTPUT */ 186 187 /* The maximum number of connections we will allocate and connect 188 * with during the test. */ 189 #define MAX_LIST_SIZE 100 190 /* The maximum finite limit we will put on requests (0 = let it 191 * run indefinately). */ 192 #define MAX_TOTAL_MAX 2000000 193 /* The maximum finite time limit we will put on the running time 194 * (0 = let it run indefiniately). */ 195 #define MAX_TIME_MAX 86400 /* one day */ 196 /* The maximum allowed response size we will accept. */ 197 #define MAX_RESPONSE_SIZE 65536 198 /* An "expectation" amount which effectively means we will keep accepting 199 * data until the server closes the connection. */ 200 #define EXPECT_SERVER_CLOSE ((unsigned int)-1) 201 /* The maximum number of seconds between stdout updates. */ 202 #define MAX_PERIOD_UPDATE 300 203 /* The size we should make the FIFO arrays */ 204 #define SWAMP_BUFFER_SIZE 2048 205 206 struct st_swamp_config { 207 /* OpenSSL "SSL_CTX" settings */ 208 const char *cacert; 209 const char *cert; 210 const char *cipher_string; 211 swamp_sslmeth sslmeth; 212 #ifdef HAVE_ENGINE 213 const char *engine_id; 214 #endif 215 /* The number of "swamp_item"s in a "swamp_thread_ctx" */ 216 unsigned long list_size; 217 /* If non-zero, the maximum number of requests before stopping */ 218 unsigned long total_max; 219 /* If non-zero, the maximum number of seconds before stopping */ 220 unsigned long time_max; 221 /* The (minimum) size to allocate our response buffer */ 222 unsigned long response_size; 223 /* How much response to expect before we are satisfied */ 224 unsigned long response_expected; 225 /* What request string to send to servers */ 226 const char *request_string; 227 /* The sequence of "s" and "r" items to control SSL_SESSION behaviour */ 228 const char *session_string; 229 /* A cached value of the string's length */ 230 unsigned int session_string_length; 231 /* A line of statistics is printed after this many seconds */ 232 unsigned long period_update; 233 /* Whether the logo should be printed or not */ 234 unsigned int nologo; 235 /* Whether each negotiated (and resumed) SSL_SESSION should be logged */ 236 unsigned int output_sessions; 237 /* If non-NULL, comma-separated output is written each second */ 238 FILE *csv_output; 239 /* The distribution pattern of 'servers' */ 240 dist_pattern *distribution; 241 }; 242 243 /* Initialise/cleanup a 'swamp_config' structure */ 244 void swamp_config_init(swamp_config *sc); 245 void swamp_config_finish(swamp_config *sc); 246 247 /* Process command-line input */ 248 int swamp_config_process_command_line(swamp_config *sc, 249 int argc, const char **argv); 250 251 /* Macro to declare a command-line switch's name */ 252 #define CMD_STR(s,v) static const char CMD_STR_##s[] = v; 253 /* Macro to declare a matching enumerated item */ 254 #define CMD_NUM(s) CMD_NUM_##s 255 /* Macro to instantiate the avaiable command strings */ 256 #define IMPLEMENT_CMDS_STRINGS_RAW \ 257 CMD_STR(SESSION_IDS, "-session_ids") \ 258 CMD_STR(NOLOGO, "-nologo") \ 259 CMD_STR(HELP1, "-h") \ 260 CMD_STR(HELP2, "-?") \ 261 CMD_STR(HELP3, "--help") \ 262 CMD_STR(CONNECT, "-connect") \ 263 CMD_STR(CAFILE, "-CAfile") \ 264 CMD_STR(CERT, "-cert") \ 265 CMD_STR(SSLMETH, "-sslmeth") \ 266 CMD_STR(NUM, "-num") \ 267 CMD_STR(COUNT, "-count") \ 268 CMD_STR(TIME, "-time") \ 269 CMD_STR(EXPECT, "-expect") \ 270 CMD_STR(REQUEST, "-request") \ 271 CMD_STR(SESSION, "-session") \ 272 CMD_STR(UPDATE, "-update") \ 273 CMD_STR(CIPHER, "-cipher") \ 274 CMD_STR(CSV, "-csv") \ 275 CMD_STR(DISTRIBUTE, "-distribute") 276 #ifndef HAVE_ENGINE 277 #define IMPLEMENT_CMDS_STRINGS IMPLEMENT_CMDS_STRINGS_RAW 278 #else 279 #define IMPLEMENT_CMDS_STRINGS \ 280 IMPLEMENT_CMDS_STRINGS_RAW \ 281 CMD_STR(ENGINE, "-engine") 282 #endif 283 /* Declare the corresponding command ids as an enumerated type */ 284 typedef enum { 285 CMD_NUM(SESSION_IDS), 286 CMD_NUM(NOLOGO), 287 CMD_NUM(HELP1), 288 CMD_NUM(HELP2), 289 CMD_NUM(HELP3), 290 CMD_NUM(CONNECT), 291 CMD_NUM(CAFILE), 292 CMD_NUM(CERT), 293 CMD_NUM(SSLMETH), 294 CMD_NUM(NUM), 295 CMD_NUM(COUNT), 296 CMD_NUM(TIME), 297 CMD_NUM(EXPECT), 298 CMD_NUM(REQUEST), 299 CMD_NUM(SESSION), 300 CMD_NUM(UPDATE), 301 CMD_NUM(CIPHER), 302 CMD_NUM(CSV), 303 CMD_NUM(DISTRIBUTE) 304 #ifdef HAVE_ENGINE 305 ,CMD_NUM(ENGINE) 306 #endif 307 } cmd_id_t; 308 /* The structure each command-line switch is represented by */ 309 typedef struct st_cmd_defn { 310 const char * cmd_name; 311 cmd_id_t cmd_id; 312 unsigned int cmd_args; 313 } cmd_defn; 314 /* Macros to declare a command-line switches with zero or one arguments */ 315 #define CMD0(s) {CMD_STR_##s, CMD_NUM_##s, 0} 316 #define CMD1(s) {CMD_STR_##s, CMD_NUM_##s, 1} 317 /* Finally, a macro to instantiate the supported list of command-switches */ 318 #define IMPLEMENT_CMDS_RAW \ 319 IMPLEMENT_CMDS_STRINGS \ 320 static const cmd_defn cmds[] = { \ 321 /* Commands that take no arguments */ \ 322 CMD0(SESSION_IDS), CMD0(NOLOGO), CMD0(HELP1), CMD0(HELP2), CMD0(HELP3), \ 323 /* Commands that take a single argument */ \ 324 CMD1(CONNECT), CMD1(CAFILE), CMD1(CERT), CMD1(SSLMETH), CMD1(NUM), CMD1(COUNT), \ 325 CMD1(TIME), CMD1(EXPECT), CMD1(REQUEST), CMD1(SESSION), CMD1(UPDATE), \ 326 CMD1(CIPHER), CMD1(CSV), CMD1(DISTRIBUTE), 327 #ifndef HAVE_ENGINE 328 #define IMPLEMENT_CMDS \ 329 IMPLEMENT_CMDS_RAW \ 330 {NULL,0,0} } 331 #else 332 #define IMPLEMENT_CMDS \ 333 IMPLEMENT_CMDS_RAW \ 334 CMD1(ENGINE), \ 335 {NULL,0,0} } 336 #endif 337 338 /*********************************************************/ 339 /* types and defines implemented/used in; dist_pattern.c */ 340 /*********************************************************/ 341 342 /* Error return codes for dist_pattern_* functions. */ 343 typedef enum { 344 ERR_DIST_PAT_OKAY = 0, 345 ERR_DIST_PAT_VALUE_OUT_OF_RANGE, 346 ERR_DIST_PAT_INVALID_SYNTAX, 347 ERR_DIST_PAT_ARRAY_FULL, 348 ERR_DIST_PAT_INTERNAL_PROBLEM 349 } dist_pattern_error_t; 350 351 void dist_pattern_up(dist_pattern *p); 352 dist_pattern *dist_pattern_new(void); 353 void dist_pattern_free(dist_pattern *dist); 354 unsigned int dist_pattern_get_start_idx(dist_pattern *p); 355 unsigned int dist_pattern_period(dist_pattern *dist); 356 unsigned int dist_pattern_num(dist_pattern *dist); 357 const NAL_ADDRESS *dist_pattern_get(const dist_pattern *dist, 358 unsigned int idx); 359 int dist_pattern_push_address(dist_pattern *dist, 360 const char *address); 361 dist_pattern_error_t dist_pattern_parse(dist_pattern *dist, 362 const char *dist_str); 363 const char *dist_pattern_error_string(dist_pattern_error_t err); 364 365 /**********************************************************/ 366 /* types and defines implemented/used in; serv_iterator.c */ 367 /**********************************************************/ 368 369 /* Create a new iterator over the supplied dist_pattern */ 370 server_iterator *server_iterator_new(dist_pattern *p); 371 /* Free an iterator */ 372 void server_iterator_free(server_iterator *c); 373 /* Return the swamp_address corresponding to our iterator on the pattern and 374 * increment the index for next time. */ 375 const NAL_ADDRESS *server_iterator_next(server_iterator *c); 376 377 #endif /* !defined(HEADER_SWAMP_H) */ 378