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