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