• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/openssl/demos/tunala/
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/* Our local types that specify our "world" */
10/********************************************/
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
15 * by thread or process IDs, and the "select" code might be replaced by
16 * message handling code. Whatever.
17 */
18typedef struct _tunala_item_t {
19    /*
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".
22     */
23    state_machine_t sm;
24    /*
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.
28     */
29    int dirty_read, dirty_send;
30    /*
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.
34     */
35    int clean_read, clean_send;
36} tunala_item_t;
37
38/*
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".
44 */
45typedef 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;
50typedef 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;
54
55/*
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).
59 */
60typedef 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;
69    /*
70     * Our SSL_CTX, which is configured as the SSL client or server and has
71     * the various cert-settings and callbacks configured.
72     */
73    SSL_CTX *ssl_ctx;
74    /*
75     * Simple flag with complex logic :-) Indicates whether we're an SSL
76     * server or an SSL client.
77     */
78    int server_mode;
79} tunala_world_t;
80
81/*****************************/
82/* Internal static functions */
83/*****************************/
84
85static 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);
94static void selector_init(tunala_selector_t * selector);
95static void selector_add_listener(tunala_selector_t * selector, int fd);
96static void selector_add_tunala(tunala_selector_t * selector,
97                                tunala_item_t * t);
98static int selector_select(tunala_selector_t * selector);
99/*
100 * This returns -1 for error, 0 for no new connections, or 1 for success, in
101 * which case *newfd is populated.
102 */
103static int selector_get_listener(tunala_selector_t * selector, int fd,
104                                 int *newfd);
105static int tunala_world_new_item(tunala_world_t * world, int fd,
106                                 const char *ip, unsigned short port,
107                                 int flipped);
108static void tunala_world_del_item(tunala_world_t * world, unsigned int idx);
109static int tunala_item_io(tunala_selector_t * selector, tunala_item_t * item);
110
111/*********************************************/
112/* MAIN FUNCTION (and its utility functions) */
113/*********************************************/
114
115static const char *def_proxyhost = "127.0.0.1:443";
116static const char *def_listenhost = "127.0.0.1:8080";
117static int def_max_tunnels = 50;
118static const char *def_cacert = NULL;
119static const char *def_cert = NULL;
120static const char *def_key = NULL;
121static const char *def_dcert = NULL;
122static const char *def_dkey = NULL;
123static const char *def_engine_id = NULL;
124static int def_server_mode = 0;
125static int def_flipped = 0;
126static const char *def_cipher_list = NULL;
127static const char *def_dh_file = NULL;
128static const char *def_dh_special = NULL;
129static int def_tmp_rsa = 1;
130static int def_ctx_options = 0;
131static int def_verify_mode = 0;
132static unsigned int def_verify_depth = 10;
133static int def_out_state = 0;
134static unsigned int def_out_verify = 0;
135static int def_out_totals = 0;
136static int def_out_conns = 0;
137
138static 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";
194
195/*
196 * Default DH parameters for use with "-dh_special standard" ... stolen
197 * striaght from s_server.
198 */
199static 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,
206};
207
208static unsigned char dh512_g[] = {
209    0x02,
210};
211
212/*
213 * And the function that parses the above "standard" parameters, again,
214 * straight out of s_server.
215 */
216static DH *get_dh512(void)
217{
218    DH *dh = NULL;
219
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);
227}
228
229/* Various help/error messages used by main() */
230static int usage(const char *errstr, int isunknownarg)
231{
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;
238}
239
240static int err_str0(const char *str0)
241{
242    fprintf(stderr, "%s\n", str0);
243    return 1;
244}
245
246static int err_str1(const char *fmt, const char *str1)
247{
248    fprintf(stderr, fmt, str1);
249    fprintf(stderr, "\n");
250    return 1;
251}
252
253static int parse_max_tunnels(const char *s, unsigned int *maxtunnels)
254{
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;
260    }
261    *maxtunnels = (unsigned int)l;
262    return 1;
263}
264
265static int parse_server_mode(const char *s, int *servermode)
266{
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;
272    }
273    *servermode = (int)l;
274    return 1;
275}
276
277static int parse_dh_special(const char *s, const char **dh_special)
278{
279    if ((strcmp(s, "NULL") == 0) || (strcmp(s, "generate") == 0) ||
280        (strcmp(s, "standard") == 0)) {
281        *dh_special = s;
282        return 1;
283    }
284    fprintf(stderr, "Error, '%s' is an invalid value for 'dh_special'\n", s);
285    return 0;
286}
287
288static int parse_verify_level(const char *s, unsigned int *verify_level)
289{
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;
295    }
296    *verify_level = (unsigned int)l;
297    return 1;
298}
299
300static int parse_verify_depth(const char *s, unsigned int *verify_depth)
301{
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;
307    }
308    *verify_depth = (unsigned int)l;
309    return 1;
310}
311
312/* Some fprintf format strings used when tunnels close */
313static const char *io_stats_dirty =
314    "    SSL traffic;   %8lu bytes in, %8lu bytes out\n";
315static const char *io_stats_clean =
316    "    clear traffic; %8lu bytes in, %8lu bytes out\n";
317
318int main(int argc, char *argv[])
319{
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;
349
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);
529    }
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");
534
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);
566
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;
581        }
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;
589    }
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);
601    }
602    /*
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.
606     */
607    loop = 0;
608    t_item = world.tunnels;
609    while (loop < world.tunnels_used) {
610        if (!tunala_item_io(&world.selector, t_item)) {
611            /*
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!
615             */
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)));
625            /*
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 :-)
629             */
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++;
644        }
645    }
646    goto main_loop;
647    /* Should never get here */
648 shouldnt_happen:
649    abort();
650    return 1;
651}
652
653/****************/
654/* OpenSSL bits */
655/****************/
656
657static int ctx_set_cert(SSL_CTX *ctx, const char *cert, const char *key)
658{
659    FILE *fp = NULL;
660    X509 *x509 = NULL;
661    EVP_PKEY *pkey = NULL;
662    int toret = 0;              /* Assume an error */
663
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;
669        }
670        if (!PEM_read_X509(fp, &x509, NULL, NULL)) {
671            fprintf(stderr, "Error reading PEM cert from '%s'\n", cert);
672            goto err;
673        }
674        if (!SSL_CTX_use_certificate(ctx, x509)) {
675            fprintf(stderr, "Error, cert in '%s' can not be used\n", cert);
676            goto err;
677        }
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);
682        /*
683         * If a cert was given without matching key, we assume the same file
684         * contains the required key.
685         */
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;
695    }
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;
701        }
702        if (!PEM_read_PrivateKey(fp, &pkey, NULL, NULL)) {
703            fprintf(stderr, "Error reading PEM key from '%s'\n", key);
704            goto err;
705        }
706        if (!SSL_CTX_use_PrivateKey(ctx, pkey)) {
707            fprintf(stderr, "Error, key in '%s' can not be used\n", key);
708            goto err;
709        }
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;
723}
724
725static int ctx_set_dh(SSL_CTX *ctx, const char *dh_file,
726                      const char *dh_special)
727{
728    DH *dh = NULL;
729    FILE *fp = NULL;
730
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;
739            }
740            fprintf(stderr, "Info, using 'standard' DH parameters\n");
741            goto do_it;
742        }
743        if (strcmp(dh_special, "generate") != 0)
744            /*
745             * This shouldn't happen - screening values is handled in main().
746             */
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;
757        }
758        fprintf(stderr, "complete\n");
759        goto do_it;
760    }
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;
766    }
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;
773    }
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;
779}
780
781static 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)
790{
791    SSL_CTX *ctx = NULL, *ret = NULL;
792    const SSL_METHOD *meth;
793    ENGINE *e = NULL;
794
795    OpenSSL_add_ssl_algorithms();
796    SSL_load_error_strings();
797
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;
807        }
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;
812        }
813        ENGINE_free(e);
814    }
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;
823        }
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;
830    }
831
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);
841
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;
847        }
848        fprintf(stderr, "Info, set cipher list '%s'\n", cipher_list);
849    } else
850        fprintf(stderr, "Info, operating with default cipher list\n");
851
852    /* dh_file & dh_special */
853    if ((dh_file || dh_special) && !ctx_set_dh(ctx, dh_file, dh_special))
854        goto err;
855
856    /* ctx_options */
857    SSL_CTX_set_options(ctx, ctx_options);
858
859    /* out_state (output of SSL handshake states to screen). */
860    if (out_state)
861        cb_ssl_info_set_output(stderr);
862
863    /* out_verify */
864    if (out_verify > 0) {
865        cb_ssl_verify_set_output(stderr);
866        cb_ssl_verify_set_level(out_verify);
867    }
868
869    /* verify_depth */
870    cb_ssl_verify_set_depth(verify_depth);
871
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);
881    }
882    return ret;
883}
884
885/*****************/
886/* Selector bits */
887/*****************/
888
889static void selector_sets_init(select_sets_t * s)
890{
891    s->max = 0;
892    FD_ZERO(&s->reads);
893    FD_ZERO(&s->sends);
894    FD_ZERO(&s->excepts);
895}
896
897static void selector_init(tunala_selector_t * selector)
898{
899    selector_sets_init(&selector->last_selected);
900    selector_sets_init(&selector->next_select);
901}
902
903#define SEL_EXCEPTS 0x00
904#define SEL_READS   0x01
905#define SEL_SENDS   0x02
906static void selector_add_raw_fd(tunala_selector_t * s, int fd, int flags)
907{
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;
916}
917
918static void selector_add_listener(tunala_selector_t * selector, int fd)
919{
920    selector_add_raw_fd(selector, fd, SEL_READS);
921}
922
923static void selector_add_tunala(tunala_selector_t * s, tunala_item_t * t)
924{
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));
931    }
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));
938    }
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));
945    }
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));
952    }
953}
954
955static int selector_select(tunala_selector_t * selector)
956{
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);
964}
965
966/*
967 * This returns -1 for error, 0 for no new connections, or 1 for success, in
968 * which case *newfd is populated.
969 */
970static int selector_get_listener(tunala_selector_t * selector, int fd,
971                                 int *newfd)
972{
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;
980}
981
982/************************/
983/* "Tunala" world stuff */
984/************************/
985
986static int tunala_world_make_room(tunala_world_t * world)
987{
988    unsigned int newsize;
989    tunala_item_t *newarray;
990
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;
1007}
1008
1009static int tunala_world_new_item(tunala_world_t * world, int fd,
1010                                 const char *ip, unsigned short port,
1011                                 int flipped)
1012{
1013    tunala_item_t *item;
1014    int newfd;
1015    SSL *new_ssl = NULL;
1016
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;
1023    }
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;
1030    /*
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. :-)
1035     */
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;
1042    }
1043    /*
1044     * We use the SSL's "app_data" to indicate a call-back induced "kill"
1045     */
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;
1053
1054}
1055
1056static void tunala_world_del_item(tunala_world_t * world, unsigned int idx)
1057{
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--;
1077}
1078
1079static int tunala_item_io(tunala_selector_t * selector, tunala_item_t * item)
1080{
1081    int c_r, c_s, d_r, d_s;     /* Four boolean flags */
1082
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;
1135    }
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;
1141    }
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;
1147    }
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;
1153    }
1154    /*
1155     * This function name is attributed to the term donated by David Schwartz
1156     * on openssl-dev, message-ID:
1157     * <NCBBLIEPOCbmasEKBEAKEEDGLIAA.davids@webmaster.com>. :-)
1158     */
1159    if (!state_machine_churn(&item->sm))
1160        /*
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.
1164         */
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;
1170    /*
1171     * If only one side closed, notify the SSL of this so it can take
1172     * appropriate action.
1173     */
1174    if ((item->clean_read == -1) || (item->clean_send == -1)) {
1175        if (!state_machine_close_clean(&item->sm))
1176            return 0;
1177    }
1178    if ((item->dirty_read == -1) || (item->dirty_send == -1)) {
1179        if (!state_machine_close_dirty(&item->sm))
1180            return 0;
1181    }
1182    return 1;
1183}
1184