summaryrefslogtreecommitdiff
path: root/src/lib/libssl/src/demos/tunala/tunala.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/libssl/src/demos/tunala/tunala.c')
-rw-r--r--src/lib/libssl/src/demos/tunala/tunala.c1109
1 files changed, 0 insertions, 1109 deletions
diff --git a/src/lib/libssl/src/demos/tunala/tunala.c b/src/lib/libssl/src/demos/tunala/tunala.c
deleted file mode 100644
index ec49d3e943..0000000000
--- a/src/lib/libssl/src/demos/tunala/tunala.c
+++ /dev/null
@@ -1,1109 +0,0 @@
1#if defined(NO_BUFFER) || defined(NO_IP) || defined(NO_OPENSSL)
2#error "Badness, NO_BUFFER, NO_IP or NO_OPENSSL is defined, turn them *off*"
3#endif
4
5/* Include our bits'n'pieces */
6#include "tunala.h"
7
8
9/********************************************/
10/* Our local types that specify our "world" */
11/********************************************/
12
13/* These represent running "tunnels". Eg. if you wanted to do SSL in a
14 * "message-passing" scanario, the "int" file-descriptors might be replaced by
15 * thread or process IDs, and the "select" code might be replaced by message
16 * handling code. Whatever. */
17typedef struct _tunala_item_t {
18 /* The underlying SSL state machine. This is a data-only processing unit
19 * and we communicate with it by talking to its four "buffers". */
20 state_machine_t sm;
21 /* The file-descriptors for the "dirty" (encrypted) side of the SSL
22 * setup. In actuality, this is typically a socket and both values are
23 * identical. */
24 int dirty_read, dirty_send;
25 /* The file-descriptors for the "clean" (unencrypted) side of the SSL
26 * setup. These could be stdin/stdout, a socket (both values the same),
27 * or whatever you like. */
28 int clean_read, clean_send;
29} tunala_item_t;
30
31/* This structure is used as the data for running the main loop. Namely, in a
32 * network format such as this, it is stuff for select() - but as pointed out,
33 * when moving the real-world to somewhere else, this might be replaced by
34 * something entirely different. It's basically the stuff that controls when
35 * it's time to do some "work". */
36typedef struct _select_sets_t {
37 int max; /* As required as the first argument to select() */
38 fd_set reads, sends, excepts; /* As passed to select() */
39} select_sets_t;
40typedef struct _tunala_selector_t {
41 select_sets_t last_selected; /* Results of the last select() */
42 select_sets_t next_select; /* What we'll next select on */
43} tunala_selector_t;
44
45/* This structure is *everything*. We do it to avoid the use of globals so that,
46 * for example, it would be easier to shift things around between async-IO,
47 * thread-based, or multi-fork()ed (or combinations thereof). */
48typedef struct _tunala_world_t {
49 /* The file-descriptor we "listen" on for new connections */
50 int listen_fd;
51 /* The array of tunnels */
52 tunala_item_t *tunnels;
53 /* the number of tunnels in use and allocated, respectively */
54 unsigned int tunnels_used, tunnels_size;
55 /* Our outside "loop" context stuff */
56 tunala_selector_t selector;
57 /* Our SSL_CTX, which is configured as the SSL client or server and has
58 * the various cert-settings and callbacks configured. */
59 SSL_CTX *ssl_ctx;
60 /* Simple flag with complex logic :-) Indicates whether we're an SSL
61 * server or an SSL client. */
62 int server_mode;
63} tunala_world_t;
64
65/*****************************/
66/* Internal static functions */
67/*****************************/
68
69static SSL_CTX *initialise_ssl_ctx(int server_mode, const char *engine_id,
70 const char *CAfile, const char *cert, const char *key,
71 const char *dcert, const char *dkey, const char *cipher_list,
72 const char *dh_file, const char *dh_special, int tmp_rsa,
73 int ctx_options, int out_state, int out_verify, int verify_mode,
74 unsigned int verify_depth);
75static void selector_init(tunala_selector_t *selector);
76static void selector_add_listener(tunala_selector_t *selector, int fd);
77static void selector_add_tunala(tunala_selector_t *selector, tunala_item_t *t);
78static int selector_select(tunala_selector_t *selector);
79/* This returns -1 for error, 0 for no new connections, or 1 for success, in
80 * which case *newfd is populated. */
81static int selector_get_listener(tunala_selector_t *selector, int fd, int *newfd);
82static int tunala_world_new_item(tunala_world_t *world, int fd,
83 const char *ip, unsigned short port, int flipped);
84static void tunala_world_del_item(tunala_world_t *world, unsigned int idx);
85static int tunala_item_io(tunala_selector_t *selector, tunala_item_t *item);
86
87/*********************************************/
88/* MAIN FUNCTION (and its utility functions) */
89/*********************************************/
90
91static const char *def_proxyhost = "127.0.0.1:443";
92static const char *def_listenhost = "127.0.0.1:8080";
93static int def_max_tunnels = 50;
94static const char *def_cacert = NULL;
95static const char *def_cert = NULL;
96static const char *def_key = NULL;
97static const char *def_dcert = NULL;
98static const char *def_dkey = NULL;
99static const char *def_engine_id = NULL;
100static int def_server_mode = 0;
101static int def_flipped = 0;
102static const char *def_cipher_list = NULL;
103static const char *def_dh_file = NULL;
104static const char *def_dh_special = NULL;
105static int def_tmp_rsa = 1;
106static int def_ctx_options = 0;
107static int def_verify_mode = 0;
108static unsigned int def_verify_depth = 10;
109static int def_out_state = 0;
110static unsigned int def_out_verify = 0;
111static int def_out_totals = 0;
112static int def_out_conns = 0;
113
114static const char *helpstring =
115"\n'Tunala' (A tunneler with a New Zealand accent)\n"
116"Usage: tunala [options], where options are from;\n"
117" -listen [host:]<port> (default = 127.0.0.1:8080)\n"
118" -proxy <host>:<port> (default = 127.0.0.1:443)\n"
119" -maxtunnels <num> (default = 50)\n"
120" -cacert <path|NULL> (default = NULL)\n"
121" -cert <path|NULL> (default = NULL)\n"
122" -key <path|NULL> (default = whatever '-cert' is)\n"
123" -dcert <path|NULL> (usually for DSA, default = NULL)\n"
124" -dkey <path|NULL> (usually for DSA, default = whatever '-dcert' is)\n"
125" -engine <id|NULL> (default = NULL)\n"
126" -server <0|1> (default = 0, ie. an SSL client)\n"
127" -flipped <0|1> (makes SSL servers be network clients, and vice versa)\n"
128" -cipher <list> (specifies cipher list to use)\n"
129" -dh_file <path> (a PEM file containing DH parameters to use)\n"
130" -dh_special <NULL|generate|standard> (see below: def=NULL)\n"
131" -no_tmp_rsa (don't generate temporary RSA keys)\n"
132" -no_ssl2 (disable SSLv2)\n"
133" -no_ssl3 (disable SSLv3)\n"
134" -no_tls1 (disable TLSv1)\n"
135" -v_peer (verify the peer certificate)\n"
136" -v_strict (do not continue if peer doesn't authenticate)\n"
137" -v_once (no verification in renegotiates)\n"
138" -v_depth <num> (limit certificate chain depth, default = 10)\n"
139" -out_conns (prints client connections and disconnections)\n"
140" -out_state (prints SSL handshake states)\n"
141" -out_verify <0|1|2|3> (prints certificate verification states: def=1)\n"
142" -out_totals (prints out byte-totals when a tunnel closes)\n"
143" -<h|help|?> (displays this help screen)\n"
144"Notes:\n"
145"(1) It is recommended to specify a cert+key when operating as an SSL server.\n"
146" If you only specify '-cert', the same file must contain a matching\n"
147" private key.\n"
148"(2) Either dh_file or dh_special can be used to specify where DH parameters\n"
149" will be obtained from (or '-dh_special NULL' for the default choice) but\n"
150" you cannot specify both. For dh_special, 'generate' will create new DH\n"
151" parameters on startup, and 'standard' will use embedded parameters\n"
152" instead.\n"
153"(3) Normally an ssl client connects to an ssl server - so that an 'ssl client\n"
154" tunala' listens for 'clean' client connections and proxies ssl, and an\n"
155" 'ssl server tunala' listens for ssl connections and proxies 'clean'. With\n"
156" '-flipped 1', this behaviour is reversed so that an 'ssl server tunala'\n"
157" listens for clean client connections and proxies ssl (but participating\n"
158" as an ssl *server* in the SSL/TLS protocol), and an 'ssl client tunala'\n"
159" listens for ssl connections (participating as an ssl *client* in the\n"
160" SSL/TLS protocol) and proxies 'clean' to the end destination. This can\n"
161" be useful for allowing network access to 'servers' where only the server\n"
162" needs to authenticate the client (ie. the other way is not required).\n"
163" Even with client and server authentication, this 'technique' mitigates\n"
164" some DoS (denial-of-service) potential as it will be the network client\n"
165" having to perform the first private key operation rather than the other\n"
166" way round.\n"
167"(4) The 'technique' used by setting '-flipped 1' is probably compatible with\n"
168" absolutely nothing except another complimentary instance of 'tunala'\n"
169" running with '-flipped 1'. :-)\n";
170
171/* Default DH parameters for use with "-dh_special standard" ... stolen striaght
172 * from s_server. */
173static unsigned char dh512_p[]={
174 0xDA,0x58,0x3C,0x16,0xD9,0x85,0x22,0x89,0xD0,0xE4,0xAF,0x75,
175 0x6F,0x4C,0xCA,0x92,0xDD,0x4B,0xE5,0x33,0xB8,0x04,0xFB,0x0F,
176 0xED,0x94,0xEF,0x9C,0x8A,0x44,0x03,0xED,0x57,0x46,0x50,0xD3,
177 0x69,0x99,0xDB,0x29,0xD7,0x76,0x27,0x6B,0xA2,0xD3,0xD4,0x12,
178 0xE2,0x18,0xF4,0xDD,0x1E,0x08,0x4C,0xF6,0xD8,0x00,0x3E,0x7C,
179 0x47,0x74,0xE8,0x33,
180 };
181static unsigned char dh512_g[]={
182 0x02,
183 };
184
185/* And the function that parses the above "standard" parameters, again, straight
186 * out of s_server. */
187static DH *get_dh512(void)
188 {
189 DH *dh=NULL;
190
191 if ((dh=DH_new()) == NULL) return(NULL);
192 dh->p=BN_bin2bn(dh512_p,sizeof(dh512_p),NULL);
193 dh->g=BN_bin2bn(dh512_g,sizeof(dh512_g),NULL);
194 if ((dh->p == NULL) || (dh->g == NULL))
195 return(NULL);
196 return(dh);
197 }
198
199/* Various help/error messages used by main() */
200static int usage(const char *errstr, int isunknownarg)
201{
202 if(isunknownarg)
203 fprintf(stderr, "Error: unknown argument '%s'\n", errstr);
204 else
205 fprintf(stderr, "Error: %s\n", errstr);
206 fprintf(stderr, "%s\n", helpstring);
207 return 1;
208}
209
210static int err_str0(const char *str0)
211{
212 fprintf(stderr, "%s\n", str0);
213 return 1;
214}
215
216static int err_str1(const char *fmt, const char *str1)
217{
218 fprintf(stderr, fmt, str1);
219 fprintf(stderr, "\n");
220 return 1;
221}
222
223static int parse_max_tunnels(const char *s, unsigned int *maxtunnels)
224{
225 unsigned long l;
226 if(!int_strtoul(s, &l) || (l < 1) || (l > 1024)) {
227 fprintf(stderr, "Error, '%s' is an invalid value for "
228 "maxtunnels\n", s);
229 return 0;
230 }
231 *maxtunnels = (unsigned int)l;
232 return 1;
233}
234
235static int parse_server_mode(const char *s, int *servermode)
236{
237 unsigned long l;
238 if(!int_strtoul(s, &l) || (l > 1)) {
239 fprintf(stderr, "Error, '%s' is an invalid value for the "
240 "server mode\n", s);
241 return 0;
242 }
243 *servermode = (int)l;
244 return 1;
245}
246
247static int parse_dh_special(const char *s, const char **dh_special)
248{
249 if((strcmp(s, "NULL") == 0) || (strcmp(s, "generate") == 0) ||
250 (strcmp(s, "standard") == 0)) {
251 *dh_special = s;
252 return 1;
253 }
254 fprintf(stderr, "Error, '%s' is an invalid value for 'dh_special'\n", s);
255 return 0;
256}
257
258static int parse_verify_level(const char *s, unsigned int *verify_level)
259{
260 unsigned long l;
261 if(!int_strtoul(s, &l) || (l > 3)) {
262 fprintf(stderr, "Error, '%s' is an invalid value for "
263 "out_verify\n", s);
264 return 0;
265 }
266 *verify_level = (unsigned int)l;
267 return 1;
268}
269
270static int parse_verify_depth(const char *s, unsigned int *verify_depth)
271{
272 unsigned long l;
273 if(!int_strtoul(s, &l) || (l < 1) || (l > 50)) {
274 fprintf(stderr, "Error, '%s' is an invalid value for "
275 "verify_depth\n", s);
276 return 0;
277 }
278 *verify_depth = (unsigned int)l;
279 return 1;
280}
281
282/* Some fprintf format strings used when tunnels close */
283static const char *io_stats_dirty =
284" SSL traffic; %8lu bytes in, %8lu bytes out\n";
285static const char *io_stats_clean =
286" clear traffic; %8lu bytes in, %8lu bytes out\n";
287
288int main(int argc, char *argv[])
289{
290 unsigned int loop;
291 int newfd;
292 tunala_world_t world;
293 tunala_item_t *t_item;
294 const char *proxy_ip;
295 unsigned short proxy_port;
296 /* Overridables */
297 const char *proxyhost = def_proxyhost;
298 const char *listenhost = def_listenhost;
299 unsigned int max_tunnels = def_max_tunnels;
300 const char *cacert = def_cacert;
301 const char *cert = def_cert;
302 const char *key = def_key;
303 const char *dcert = def_dcert;
304 const char *dkey = def_dkey;
305 const char *engine_id = def_engine_id;
306 int server_mode = def_server_mode;
307 int flipped = def_flipped;
308 const char *cipher_list = def_cipher_list;
309 const char *dh_file = def_dh_file;
310 const char *dh_special = def_dh_special;
311 int tmp_rsa = def_tmp_rsa;
312 int ctx_options = def_ctx_options;
313 int verify_mode = def_verify_mode;
314 unsigned int verify_depth = def_verify_depth;
315 int out_state = def_out_state;
316 unsigned int out_verify = def_out_verify;
317 int out_totals = def_out_totals;
318 int out_conns = def_out_conns;
319
320/* Parse command-line arguments */
321next_arg:
322 argc--; argv++;
323 if(argc > 0) {
324 if(strcmp(*argv, "-listen") == 0) {
325 if(argc < 2)
326 return usage("-listen requires an argument", 0);
327 argc--; argv++;
328 listenhost = *argv;
329 goto next_arg;
330 } else if(strcmp(*argv, "-proxy") == 0) {
331 if(argc < 2)
332 return usage("-proxy requires an argument", 0);
333 argc--; argv++;
334 proxyhost = *argv;
335 goto next_arg;
336 } else if(strcmp(*argv, "-maxtunnels") == 0) {
337 if(argc < 2)
338 return usage("-maxtunnels requires an argument", 0);
339 argc--; argv++;
340 if(!parse_max_tunnels(*argv, &max_tunnels))
341 return 1;
342 goto next_arg;
343 } else if(strcmp(*argv, "-cacert") == 0) {
344 if(argc < 2)
345 return usage("-cacert requires an argument", 0);
346 argc--; argv++;
347 if(strcmp(*argv, "NULL") == 0)
348 cacert = NULL;
349 else
350 cacert = *argv;
351 goto next_arg;
352 } else if(strcmp(*argv, "-cert") == 0) {
353 if(argc < 2)
354 return usage("-cert requires an argument", 0);
355 argc--; argv++;
356 if(strcmp(*argv, "NULL") == 0)
357 cert = NULL;
358 else
359 cert = *argv;
360 goto next_arg;
361 } else if(strcmp(*argv, "-key") == 0) {
362 if(argc < 2)
363 return usage("-key requires an argument", 0);
364 argc--; argv++;
365 if(strcmp(*argv, "NULL") == 0)
366 key = NULL;
367 else
368 key = *argv;
369 goto next_arg;
370 } else if(strcmp(*argv, "-dcert") == 0) {
371 if(argc < 2)
372 return usage("-dcert requires an argument", 0);
373 argc--; argv++;
374 if(strcmp(*argv, "NULL") == 0)
375 dcert = NULL;
376 else
377 dcert = *argv;
378 goto next_arg;
379 } else if(strcmp(*argv, "-dkey") == 0) {
380 if(argc < 2)
381 return usage("-dkey requires an argument", 0);
382 argc--; argv++;
383 if(strcmp(*argv, "NULL") == 0)
384 dkey = NULL;
385 else
386 dkey = *argv;
387 goto next_arg;
388 } else if(strcmp(*argv, "-engine") == 0) {
389 if(argc < 2)
390 return usage("-engine requires an argument", 0);
391 argc--; argv++;
392 engine_id = *argv;
393 goto next_arg;
394 } else if(strcmp(*argv, "-server") == 0) {
395 if(argc < 2)
396 return usage("-server requires an argument", 0);
397 argc--; argv++;
398 if(!parse_server_mode(*argv, &server_mode))
399 return 1;
400 goto next_arg;
401 } else if(strcmp(*argv, "-flipped") == 0) {
402 if(argc < 2)
403 return usage("-flipped requires an argument", 0);
404 argc--; argv++;
405 if(!parse_server_mode(*argv, &flipped))
406 return 1;
407 goto next_arg;
408 } else if(strcmp(*argv, "-cipher") == 0) {
409 if(argc < 2)
410 return usage("-cipher requires an argument", 0);
411 argc--; argv++;
412 cipher_list = *argv;
413 goto next_arg;
414 } else if(strcmp(*argv, "-dh_file") == 0) {
415 if(argc < 2)
416 return usage("-dh_file requires an argument", 0);
417 if(dh_special)
418 return usage("cannot mix -dh_file with "
419 "-dh_special", 0);
420 argc--; argv++;
421 dh_file = *argv;
422 goto next_arg;
423 } else if(strcmp(*argv, "-dh_special") == 0) {
424 if(argc < 2)
425 return usage("-dh_special requires an argument", 0);
426 if(dh_file)
427 return usage("cannot mix -dh_file with "
428 "-dh_special", 0);
429 argc--; argv++;
430 if(!parse_dh_special(*argv, &dh_special))
431 return 1;
432 goto next_arg;
433 } else if(strcmp(*argv, "-no_tmp_rsa") == 0) {
434 tmp_rsa = 0;
435 goto next_arg;
436 } else if(strcmp(*argv, "-no_ssl2") == 0) {
437 ctx_options |= SSL_OP_NO_SSLv2;
438 goto next_arg;
439 } else if(strcmp(*argv, "-no_ssl3") == 0) {
440 ctx_options |= SSL_OP_NO_SSLv3;
441 goto next_arg;
442 } else if(strcmp(*argv, "-no_tls1") == 0) {
443 ctx_options |= SSL_OP_NO_TLSv1;
444 goto next_arg;
445 } else if(strcmp(*argv, "-v_peer") == 0) {
446 verify_mode |= SSL_VERIFY_PEER;
447 goto next_arg;
448 } else if(strcmp(*argv, "-v_strict") == 0) {
449 verify_mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
450 goto next_arg;
451 } else if(strcmp(*argv, "-v_once") == 0) {
452 verify_mode |= SSL_VERIFY_CLIENT_ONCE;
453 goto next_arg;
454 } else if(strcmp(*argv, "-v_depth") == 0) {
455 if(argc < 2)
456 return usage("-v_depth requires an argument", 0);
457 argc--; argv++;
458 if(!parse_verify_depth(*argv, &verify_depth))
459 return 1;
460 goto next_arg;
461 } else if(strcmp(*argv, "-out_state") == 0) {
462 out_state = 1;
463 goto next_arg;
464 } else if(strcmp(*argv, "-out_verify") == 0) {
465 if(argc < 2)
466 return usage("-out_verify requires an argument", 0);
467 argc--; argv++;
468 if(!parse_verify_level(*argv, &out_verify))
469 return 1;
470 goto next_arg;
471 } else if(strcmp(*argv, "-out_totals") == 0) {
472 out_totals = 1;
473 goto next_arg;
474 } else if(strcmp(*argv, "-out_conns") == 0) {
475 out_conns = 1;
476 goto next_arg;
477 } else if((strcmp(*argv, "-h") == 0) ||
478 (strcmp(*argv, "-help") == 0) ||
479 (strcmp(*argv, "-?") == 0)) {
480 fprintf(stderr, "%s\n", helpstring);
481 return 0;
482 } else
483 return usage(*argv, 1);
484 }
485 /* Run any sanity checks we want here */
486 if(!cert && !dcert && server_mode)
487 fprintf(stderr, "WARNING: you are running an SSL server without "
488 "a certificate - this may not work!\n");
489
490 /* Initialise network stuff */
491 if(!ip_initialise())
492 return err_str0("ip_initialise failed");
493 /* Create the SSL_CTX */
494 if((world.ssl_ctx = initialise_ssl_ctx(server_mode, engine_id,
495 cacert, cert, key, dcert, dkey, cipher_list, dh_file,
496 dh_special, tmp_rsa, ctx_options, out_state, out_verify,
497 verify_mode, verify_depth)) == NULL)
498 return err_str1("initialise_ssl_ctx(engine_id=%s) failed",
499 (engine_id == NULL) ? "NULL" : engine_id);
500 if(engine_id)
501 fprintf(stderr, "Info, engine '%s' initialised\n", engine_id);
502 /* Create the listener */
503 if((world.listen_fd = ip_create_listener(listenhost)) == -1)
504 return err_str1("ip_create_listener(%s) failed", listenhost);
505 fprintf(stderr, "Info, listening on '%s'\n", listenhost);
506 if(!ip_parse_address(proxyhost, &proxy_ip, &proxy_port, 0))
507 return err_str1("ip_parse_address(%s) failed", proxyhost);
508 fprintf(stderr, "Info, proxying to '%s' (%d.%d.%d.%d:%d)\n", proxyhost,
509 (int)proxy_ip[0], (int)proxy_ip[1],
510 (int)proxy_ip[2], (int)proxy_ip[3], (int)proxy_port);
511 fprintf(stderr, "Info, set maxtunnels to %d\n", (int)max_tunnels);
512 fprintf(stderr, "Info, set to operate as an SSL %s\n",
513 (server_mode ? "server" : "client"));
514 /* Initialise the rest of the stuff */
515 world.tunnels_used = world.tunnels_size = 0;
516 world.tunnels = NULL;
517 world.server_mode = server_mode;
518 selector_init(&world.selector);
519
520/* We're ready to loop */
521main_loop:
522 /* Should we listen for *new* tunnels? */
523 if(world.tunnels_used < max_tunnels)
524 selector_add_listener(&world.selector, world.listen_fd);
525 /* We should add in our existing tunnels */
526 for(loop = 0; loop < world.tunnels_used; loop++)
527 selector_add_tunala(&world.selector, world.tunnels + loop);
528 /* Now do the select */
529 switch(selector_select(&world.selector)) {
530 case -1:
531 if(errno != EINTR) {
532 fprintf(stderr, "selector_select returned a "
533 "badness error.\n");
534 goto shouldnt_happen;
535 }
536 fprintf(stderr, "Warn, selector interrupted by a signal\n");
537 goto main_loop;
538 case 0:
539 fprintf(stderr, "Warn, selector_select returned 0 - signal?""?\n");
540 goto main_loop;
541 default:
542 break;
543 }
544 /* Accept new connection if we should and can */
545 if((world.tunnels_used < max_tunnels) && (selector_get_listener(
546 &world.selector, world.listen_fd,
547 &newfd) == 1)) {
548 /* We have a new connection */
549 if(!tunala_world_new_item(&world, newfd, proxy_ip,
550 proxy_port, flipped))
551 fprintf(stderr, "tunala_world_new_item failed\n");
552 else if(out_conns)
553 fprintf(stderr, "Info, new tunnel opened, now up to "
554 "%d\n", world.tunnels_used);
555 }
556 /* Give each tunnel its moment, note the while loop is because it makes
557 * the logic easier than with "for" to deal with an array that may shift
558 * because of deletes. */
559 loop = 0;
560 t_item = world.tunnels;
561 while(loop < world.tunnels_used) {
562 if(!tunala_item_io(&world.selector, t_item)) {
563 /* We're closing whether for reasons of an error or a
564 * natural close. Don't increment loop or t_item because
565 * the next item is moving to us! */
566 if(!out_totals)
567 goto skip_totals;
568 fprintf(stderr, "Tunnel closing, traffic stats follow\n");
569 /* Display the encrypted (over the network) stats */
570 fprintf(stderr, io_stats_dirty,
571 buffer_total_in(state_machine_get_buffer(
572 &t_item->sm,SM_DIRTY_IN)),
573 buffer_total_out(state_machine_get_buffer(
574 &t_item->sm,SM_DIRTY_OUT)));
575 /* Display the local (tunnelled) stats. NB: Data we
576 * *receive* is data sent *out* of the state_machine on
577 * its 'clean' side. Hence the apparent back-to-front
578 * OUT/IN mixup here :-) */
579 fprintf(stderr, io_stats_clean,
580 buffer_total_out(state_machine_get_buffer(
581 &t_item->sm,SM_CLEAN_OUT)),
582 buffer_total_in(state_machine_get_buffer(
583 &t_item->sm,SM_CLEAN_IN)));
584skip_totals:
585 tunala_world_del_item(&world, loop);
586 if(out_conns)
587 fprintf(stderr, "Info, tunnel closed, down to %d\n",
588 world.tunnels_used);
589 }
590 else {
591 /* Move to the next item */
592 loop++;
593 t_item++;
594 }
595 }
596 goto main_loop;
597 /* Should never get here */
598shouldnt_happen:
599 abort();
600 return 1;
601}
602
603/****************/
604/* OpenSSL bits */
605/****************/
606
607static int ctx_set_cert(SSL_CTX *ctx, const char *cert, const char *key)
608{
609 FILE *fp = NULL;
610 X509 *x509 = NULL;
611 EVP_PKEY *pkey = NULL;
612 int toret = 0; /* Assume an error */
613
614 /* cert */
615 if(cert) {
616 if((fp = fopen(cert, "r")) == NULL) {
617 fprintf(stderr, "Error opening cert file '%s'\n", cert);
618 goto err;
619 }
620 if(!PEM_read_X509(fp, &x509, NULL, NULL)) {
621 fprintf(stderr, "Error reading PEM cert from '%s'\n",
622 cert);
623 goto err;
624 }
625 if(!SSL_CTX_use_certificate(ctx, x509)) {
626 fprintf(stderr, "Error, cert in '%s' can not be used\n",
627 cert);
628 goto err;
629 }
630 /* Clear the FILE* for reuse in the "key" code */
631 fclose(fp);
632 fp = NULL;
633 fprintf(stderr, "Info, operating with cert in '%s'\n", cert);
634 /* If a cert was given without matching key, we assume the same
635 * file contains the required key. */
636 if(!key)
637 key = cert;
638 } else {
639 if(key)
640 fprintf(stderr, "Error, can't specify a key without a "
641 "corresponding certificate\n");
642 else
643 fprintf(stderr, "Error, ctx_set_cert called with "
644 "NULLs!\n");
645 goto err;
646 }
647 /* key */
648 if(key) {
649 if((fp = fopen(key, "r")) == NULL) {
650 fprintf(stderr, "Error opening key file '%s'\n", key);
651 goto err;
652 }
653 if(!PEM_read_PrivateKey(fp, &pkey, NULL, NULL)) {
654 fprintf(stderr, "Error reading PEM key from '%s'\n",
655 key);
656 goto err;
657 }
658 if(!SSL_CTX_use_PrivateKey(ctx, pkey)) {
659 fprintf(stderr, "Error, key in '%s' can not be used\n",
660 key);
661 goto err;
662 }
663 fprintf(stderr, "Info, operating with key in '%s'\n", key);
664 } else
665 fprintf(stderr, "Info, operating without a cert or key\n");
666 /* Success */
667 toret = 1; err:
668 if(x509)
669 X509_free(x509);
670 if(pkey)
671 EVP_PKEY_free(pkey);
672 if(fp)
673 fclose(fp);
674 return toret;
675}
676
677static int ctx_set_dh(SSL_CTX *ctx, const char *dh_file, const char *dh_special)
678{
679 DH *dh = NULL;
680 FILE *fp = NULL;
681
682 if(dh_special) {
683 if(strcmp(dh_special, "NULL") == 0)
684 return 1;
685 if(strcmp(dh_special, "standard") == 0) {
686 if((dh = get_dh512()) == NULL) {
687 fprintf(stderr, "Error, can't parse 'standard'"
688 " DH parameters\n");
689 return 0;
690 }
691 fprintf(stderr, "Info, using 'standard' DH parameters\n");
692 goto do_it;
693 }
694 if(strcmp(dh_special, "generate") != 0)
695 /* This shouldn't happen - screening values is handled
696 * in main(). */
697 abort();
698 fprintf(stderr, "Info, generating DH parameters ... ");
699 fflush(stderr);
700 if(!(dh = DH_new()) || !DH_generate_parameters_ex(dh, 512,
701 DH_GENERATOR_5, NULL)) {
702 fprintf(stderr, "error!\n");
703 if(dh)
704 DH_free(dh);
705 return 0;
706 }
707 fprintf(stderr, "complete\n");
708 goto do_it;
709 }
710 /* So, we're loading dh_file */
711 if((fp = fopen(dh_file, "r")) == NULL) {
712 fprintf(stderr, "Error, couldn't open '%s' for DH parameters\n",
713 dh_file);
714 return 0;
715 }
716 dh = PEM_read_DHparams(fp, NULL, NULL, NULL);
717 fclose(fp);
718 if(dh == NULL) {
719 fprintf(stderr, "Error, could not parse DH parameters from '%s'\n",
720 dh_file);
721 return 0;
722 }
723 fprintf(stderr, "Info, using DH parameters from file '%s'\n", dh_file);
724do_it:
725 SSL_CTX_set_tmp_dh(ctx, dh);
726 DH_free(dh);
727 return 1;
728}
729
730static SSL_CTX *initialise_ssl_ctx(int server_mode, const char *engine_id,
731 const char *CAfile, const char *cert, const char *key,
732 const char *dcert, const char *dkey, const char *cipher_list,
733 const char *dh_file, const char *dh_special, int tmp_rsa,
734 int ctx_options, int out_state, int out_verify, int verify_mode,
735 unsigned int verify_depth)
736{
737 SSL_CTX *ctx = NULL, *ret = NULL;
738 const SSL_METHOD *meth;
739 ENGINE *e = NULL;
740
741 OpenSSL_add_ssl_algorithms();
742 SSL_load_error_strings();
743
744 meth = (server_mode ? SSLv23_server_method() : SSLv23_client_method());
745 if(meth == NULL)
746 goto err;
747 if(engine_id) {
748 ENGINE_load_builtin_engines();
749 if((e = ENGINE_by_id(engine_id)) == NULL) {
750 fprintf(stderr, "Error obtaining '%s' engine, openssl "
751 "errors follow\n", engine_id);
752 goto err;
753 }
754 if(!ENGINE_set_default(e, ENGINE_METHOD_ALL)) {
755 fprintf(stderr, "Error assigning '%s' engine, openssl "
756 "errors follow\n", engine_id);
757 goto err;
758 }
759 ENGINE_free(e);
760 }
761 if((ctx = SSL_CTX_new(meth)) == NULL)
762 goto err;
763 /* cacert */
764 if(CAfile) {
765 if(!X509_STORE_load_locations(SSL_CTX_get_cert_store(ctx),
766 CAfile, NULL)) {
767 fprintf(stderr, "Error loading CA cert(s) in '%s'\n",
768 CAfile);
769 goto err;
770 }
771 fprintf(stderr, "Info, operating with CA cert(s) in '%s'\n",
772 CAfile);
773 } else
774 fprintf(stderr, "Info, operating without a CA cert(-list)\n");
775 if(!SSL_CTX_set_default_verify_paths(ctx)) {
776 fprintf(stderr, "Error setting default verify paths\n");
777 goto err;
778 }
779
780 /* cert and key */
781 if((cert || key) && !ctx_set_cert(ctx, cert, key))
782 goto err;
783 /* dcert and dkey */
784 if((dcert || dkey) && !ctx_set_cert(ctx, dcert, dkey))
785 goto err;
786 /* temporary RSA key generation */
787 if(tmp_rsa)
788 SSL_CTX_set_tmp_rsa_callback(ctx, cb_generate_tmp_rsa);
789
790 /* cipher_list */
791 if(cipher_list) {
792 if(!SSL_CTX_set_cipher_list(ctx, cipher_list)) {
793 fprintf(stderr, "Error setting cipher list '%s'\n",
794 cipher_list);
795 goto err;
796 }
797 fprintf(stderr, "Info, set cipher list '%s'\n", cipher_list);
798 } else
799 fprintf(stderr, "Info, operating with default cipher list\n");
800
801 /* dh_file & dh_special */
802 if((dh_file || dh_special) && !ctx_set_dh(ctx, dh_file, dh_special))
803 goto err;
804
805 /* ctx_options */
806 SSL_CTX_set_options(ctx, ctx_options);
807
808 /* out_state (output of SSL handshake states to screen). */
809 if(out_state)
810 cb_ssl_info_set_output(stderr);
811
812 /* out_verify */
813 if(out_verify > 0) {
814 cb_ssl_verify_set_output(stderr);
815 cb_ssl_verify_set_level(out_verify);
816 }
817
818 /* verify_depth */
819 cb_ssl_verify_set_depth(verify_depth);
820
821 /* Success! (includes setting verify_mode) */
822 SSL_CTX_set_info_callback(ctx, cb_ssl_info);
823 SSL_CTX_set_verify(ctx, verify_mode, cb_ssl_verify);
824 ret = ctx;
825err:
826 if(!ret) {
827 ERR_print_errors_fp(stderr);
828 if(ctx)
829 SSL_CTX_free(ctx);
830 }
831 return ret;
832}
833
834/*****************/
835/* Selector bits */
836/*****************/
837
838static void selector_sets_init(select_sets_t *s)
839{
840 s->max = 0;
841 FD_ZERO(&s->reads);
842 FD_ZERO(&s->sends);
843 FD_ZERO(&s->excepts);
844}
845static void selector_init(tunala_selector_t *selector)
846{
847 selector_sets_init(&selector->last_selected);
848 selector_sets_init(&selector->next_select);
849}
850
851#define SEL_EXCEPTS 0x00
852#define SEL_READS 0x01
853#define SEL_SENDS 0x02
854static void selector_add_raw_fd(tunala_selector_t *s, int fd, int flags)
855{
856 FD_SET(fd, &s->next_select.excepts);
857 if(flags & SEL_READS)
858 FD_SET(fd, &s->next_select.reads);
859 if(flags & SEL_SENDS)
860 FD_SET(fd, &s->next_select.sends);
861 /* Adjust "max" */
862 if(s->next_select.max < (fd + 1))
863 s->next_select.max = fd + 1;
864}
865
866static void selector_add_listener(tunala_selector_t *selector, int fd)
867{
868 selector_add_raw_fd(selector, fd, SEL_READS);
869}
870
871static void selector_add_tunala(tunala_selector_t *s, tunala_item_t *t)
872{
873 /* Set clean read if sm.clean_in is not full */
874 if(t->clean_read != -1) {
875 selector_add_raw_fd(s, t->clean_read,
876 (buffer_full(state_machine_get_buffer(&t->sm,
877 SM_CLEAN_IN)) ? SEL_EXCEPTS : SEL_READS));
878 }
879 /* Set clean send if sm.clean_out is not empty */
880 if(t->clean_send != -1) {
881 selector_add_raw_fd(s, t->clean_send,
882 (buffer_empty(state_machine_get_buffer(&t->sm,
883 SM_CLEAN_OUT)) ? SEL_EXCEPTS : SEL_SENDS));
884 }
885 /* Set dirty read if sm.dirty_in is not full */
886 if(t->dirty_read != -1) {
887 selector_add_raw_fd(s, t->dirty_read,
888 (buffer_full(state_machine_get_buffer(&t->sm,
889 SM_DIRTY_IN)) ? SEL_EXCEPTS : SEL_READS));
890 }
891 /* Set dirty send if sm.dirty_out is not empty */
892 if(t->dirty_send != -1) {
893 selector_add_raw_fd(s, t->dirty_send,
894 (buffer_empty(state_machine_get_buffer(&t->sm,
895 SM_DIRTY_OUT)) ? SEL_EXCEPTS : SEL_SENDS));
896 }
897}
898
899static int selector_select(tunala_selector_t *selector)
900{
901 memcpy(&selector->last_selected, &selector->next_select,
902 sizeof(select_sets_t));
903 selector_sets_init(&selector->next_select);
904 return select(selector->last_selected.max,
905 &selector->last_selected.reads,
906 &selector->last_selected.sends,
907 &selector->last_selected.excepts, NULL);
908}
909
910/* This returns -1 for error, 0 for no new connections, or 1 for success, in
911 * which case *newfd is populated. */
912static int selector_get_listener(tunala_selector_t *selector, int fd, int *newfd)
913{
914 if(FD_ISSET(fd, &selector->last_selected.excepts))
915 return -1;
916 if(!FD_ISSET(fd, &selector->last_selected.reads))
917 return 0;
918 if((*newfd = ip_accept_connection(fd)) == -1)
919 return -1;
920 return 1;
921}
922
923/************************/
924/* "Tunala" world stuff */
925/************************/
926
927static int tunala_world_make_room(tunala_world_t *world)
928{
929 unsigned int newsize;
930 tunala_item_t *newarray;
931
932 if(world->tunnels_used < world->tunnels_size)
933 return 1;
934 newsize = (world->tunnels_size == 0 ? 16 :
935 ((world->tunnels_size * 3) / 2));
936 if((newarray = malloc(newsize * sizeof(tunala_item_t))) == NULL)
937 return 0;
938 memset(newarray, 0, newsize * sizeof(tunala_item_t));
939 if(world->tunnels_used > 0)
940 memcpy(newarray, world->tunnels,
941 world->tunnels_used * sizeof(tunala_item_t));
942 if(world->tunnels_size > 0)
943 free(world->tunnels);
944 /* migrate */
945 world->tunnels = newarray;
946 world->tunnels_size = newsize;
947 return 1;
948}
949
950static int tunala_world_new_item(tunala_world_t *world, int fd,
951 const char *ip, unsigned short port, int flipped)
952{
953 tunala_item_t *item;
954 int newfd;
955 SSL *new_ssl = NULL;
956
957 if(!tunala_world_make_room(world))
958 return 0;
959 if((new_ssl = SSL_new(world->ssl_ctx)) == NULL) {
960 fprintf(stderr, "Error creating new SSL\n");
961 ERR_print_errors_fp(stderr);
962 return 0;
963 }
964 item = world->tunnels + (world->tunnels_used++);
965 state_machine_init(&item->sm);
966 item->clean_read = item->clean_send =
967 item->dirty_read = item->dirty_send = -1;
968 if((newfd = ip_create_connection_split(ip, port)) == -1)
969 goto err;
970 /* Which way round? If we're a server, "fd" is the dirty side and the
971 * connection we open is the clean one. For a client, it's the other way
972 * around. Unless, of course, we're "flipped" in which case everything
973 * gets reversed. :-) */
974 if((world->server_mode && !flipped) ||
975 (!world->server_mode && flipped)) {
976 item->dirty_read = item->dirty_send = fd;
977 item->clean_read = item->clean_send = newfd;
978 } else {
979 item->clean_read = item->clean_send = fd;
980 item->dirty_read = item->dirty_send = newfd;
981 }
982 /* We use the SSL's "app_data" to indicate a call-back induced "kill" */
983 SSL_set_app_data(new_ssl, NULL);
984 if(!state_machine_set_SSL(&item->sm, new_ssl, world->server_mode))
985 goto err;
986 return 1;
987err:
988 tunala_world_del_item(world, world->tunnels_used - 1);
989 return 0;
990
991}
992
993static void tunala_world_del_item(tunala_world_t *world, unsigned int idx)
994{
995 tunala_item_t *item = world->tunnels + idx;
996 if(item->clean_read != -1)
997 close(item->clean_read);
998 if(item->clean_send != item->clean_read)
999 close(item->clean_send);
1000 item->clean_read = item->clean_send = -1;
1001 if(item->dirty_read != -1)
1002 close(item->dirty_read);
1003 if(item->dirty_send != item->dirty_read)
1004 close(item->dirty_send);
1005 item->dirty_read = item->dirty_send = -1;
1006 state_machine_close(&item->sm);
1007 /* OK, now we fix the item array */
1008 if(idx + 1 < world->tunnels_used)
1009 /* We need to scroll entries to the left */
1010 memmove(world->tunnels + idx,
1011 world->tunnels + (idx + 1),
1012 (world->tunnels_used - (idx + 1)) *
1013 sizeof(tunala_item_t));
1014 world->tunnels_used--;
1015}
1016
1017static int tunala_item_io(tunala_selector_t *selector, tunala_item_t *item)
1018{
1019 int c_r, c_s, d_r, d_s; /* Four boolean flags */
1020
1021 /* Take ourselves out of the gene-pool if there was an except */
1022 if((item->clean_read != -1) && FD_ISSET(item->clean_read,
1023 &selector->last_selected.excepts))
1024 return 0;
1025 if((item->clean_send != -1) && FD_ISSET(item->clean_send,
1026 &selector->last_selected.excepts))
1027 return 0;
1028 if((item->dirty_read != -1) && FD_ISSET(item->dirty_read,
1029 &selector->last_selected.excepts))
1030 return 0;
1031 if((item->dirty_send != -1) && FD_ISSET(item->dirty_send,
1032 &selector->last_selected.excepts))
1033 return 0;
1034 /* Grab our 4 IO flags */
1035 c_r = c_s = d_r = d_s = 0;
1036 if(item->clean_read != -1)
1037 c_r = FD_ISSET(item->clean_read, &selector->last_selected.reads);
1038 if(item->clean_send != -1)
1039 c_s = FD_ISSET(item->clean_send, &selector->last_selected.sends);
1040 if(item->dirty_read != -1)
1041 d_r = FD_ISSET(item->dirty_read, &selector->last_selected.reads);
1042 if(item->dirty_send != -1)
1043 d_s = FD_ISSET(item->dirty_send, &selector->last_selected.sends);
1044 /* If no IO has happened for us, skip needless data looping */
1045 if(!c_r && !c_s && !d_r && !d_s)
1046 return 1;
1047 if(c_r)
1048 c_r = (buffer_from_fd(state_machine_get_buffer(&item->sm,
1049 SM_CLEAN_IN), item->clean_read) <= 0);
1050 if(c_s)
1051 c_s = (buffer_to_fd(state_machine_get_buffer(&item->sm,
1052 SM_CLEAN_OUT), item->clean_send) <= 0);
1053 if(d_r)
1054 d_r = (buffer_from_fd(state_machine_get_buffer(&item->sm,
1055 SM_DIRTY_IN), item->dirty_read) <= 0);
1056 if(d_s)
1057 d_s = (buffer_to_fd(state_machine_get_buffer(&item->sm,
1058 SM_DIRTY_OUT), item->dirty_send) <= 0);
1059 /* If any of the flags is non-zero, that means they need closing */
1060 if(c_r) {
1061 close(item->clean_read);
1062 if(item->clean_send == item->clean_read)
1063 item->clean_send = -1;
1064 item->clean_read = -1;
1065 }
1066 if(c_s && (item->clean_send != -1)) {
1067 close(item->clean_send);
1068 if(item->clean_send == item->clean_read)
1069 item->clean_read = -1;
1070 item->clean_send = -1;
1071 }
1072 if(d_r) {
1073 close(item->dirty_read);
1074 if(item->dirty_send == item->dirty_read)
1075 item->dirty_send = -1;
1076 item->dirty_read = -1;
1077 }
1078 if(d_s && (item->dirty_send != -1)) {
1079 close(item->dirty_send);
1080 if(item->dirty_send == item->dirty_read)
1081 item->dirty_read = -1;
1082 item->dirty_send = -1;
1083 }
1084 /* This function name is attributed to the term donated by David
1085 * Schwartz on openssl-dev, message-ID:
1086 * <NCBBLIEPOCNJOAEKBEAKEEDGLIAA.davids@webmaster.com>. :-) */
1087 if(!state_machine_churn(&item->sm))
1088 /* If the SSL closes, it will also zero-out the _in buffers
1089 * and will in future process just outgoing data. As and
1090 * when the outgoing data has gone, it will return zero
1091 * here to tell us to bail out. */
1092 return 0;
1093 /* Otherwise, we return zero if both sides are dead. */
1094 if(((item->clean_read == -1) || (item->clean_send == -1)) &&
1095 ((item->dirty_read == -1) || (item->dirty_send == -1)))
1096 return 0;
1097 /* If only one side closed, notify the SSL of this so it can take
1098 * appropriate action. */
1099 if((item->clean_read == -1) || (item->clean_send == -1)) {
1100 if(!state_machine_close_clean(&item->sm))
1101 return 0;
1102 }
1103 if((item->dirty_read == -1) || (item->dirty_send == -1)) {
1104 if(!state_machine_close_dirty(&item->sm))
1105 return 0;
1106 }
1107 return 1;
1108}
1109