#if defined(NO_BUFFER) || defined(NO_IP) || defined(NO_OPENSSL)
#error "Badness, NO_BUFFER, NO_IP or NO_OPENSSL is defined, turn them *off*"
#endif
/* Include our bits'n'pieces */
#include "tunala.h"
/********************************************/
/* Our local types that specify our "world" */
/********************************************/
/* These represent running "tunnels". Eg. if you wanted to do SSL in a
* "message-passing" scanario, the "int" file-descriptors might be replaced by
* thread or process IDs, and the "select" code might be replaced by message
* handling code. Whatever. */
typedef struct _tunala_item_t {
/* The underlying SSL state machine. This is a data-only processing unit
* and we communicate with it by talking to its four "buffers". */
state_machine_t sm;
/* The file-descriptors for the "dirty" (encrypted) side of the SSL
* setup. In actuality, this is typically a socket and both values are
* identical. */
int dirty_read, dirty_send;
/* The file-descriptors for the "clean" (unencrypted) side of the SSL
* setup. These could be stdin/stdout, a socket (both values the same),
* or whatever you like. */
int clean_read, clean_send;
} tunala_item_t;
/* This structure is used as the data for running the main loop. Namely, in a
* network format such as this, it is stuff for select() - but as pointed out,
* when moving the real-world to somewhere else, this might be replaced by
* something entirely different. It's basically the stuff that controls when
* it's time to do some "work". */
typedef struct _select_sets_t {
int max; /* As required as the first argument to select() */
fd_set reads, sends, excepts; /* As passed to select() */
} select_sets_t;
typedef struct _tunala_selector_t {
select_sets_t last_selected; /* Results of the last select() */
select_sets_t next_select; /* What we'll next select on */
} tunala_selector_t;
/* This structure is *everything*. We do it to avoid the use of globals so that,
* for example, it would be easier to shift things around between async-IO,
* thread-based, or multi-fork()ed (or combinations thereof). */
typedef struct _tunala_world_t {
/* The file-descriptor we "listen" on for new connections */
int listen_fd;
/* The array of tunnels */
tunala_item_t *tunnels;
/* the number of tunnels in use and allocated, respectively */
unsigned int tunnels_used, tunnels_size;
/* Our outside "loop" context stuff */
tunala_selector_t selector;
/* Our SSL_CTX, which is configured as the SSL client or server and has
* the various cert-settings and callbacks configured. */
SSL_CTX *ssl_ctx;
/* Simple flag with complex logic :-) Indicates whether we're an SSL
* server or an SSL client. */
int server_mode;
} tunala_world_t;
/*****************************/
/* Internal static functions */
/*****************************/
static SSL_CTX *initialise_ssl_ctx(int server_mode, const char *engine_id,
const char *CAfile, const char *cert, const char *key,
const char *dcert, const char *dkey, const char *cipher_list,
const char *dh_file, const char *dh_special, int ctx_options,
int out_state, int out_verify, int verify_mode,
unsigned int verify_depth);
static void selector_init(tunala_selector_t *selector);
static void selector_add_listener(tunala_selector_t *selector, int fd);
static void selector_add_tunala(tunala_selector_t *selector, tunala_item_t *t);
static int selector_select(tunala_selector_t *selector);
/* This returns -1 for error, 0 for no new connections, or 1 for success, in
* which case *newfd is populated. */
static int selector_get_listener(tunala_selector_t *selector, int fd, int *newfd);
static int tunala_world_new_item(tunala_world_t *world, int fd,
const unsigned char *ip, unsigned short port, int flipped);
static void tunala_world_del_item(tunala_world_t *world, unsigned int idx);
static int tunala_item_io(tunala_selector_t *selector, tunala_item_t *item);
/*********************************************/
/* MAIN FUNCTION (and its utility functions) */
/*********************************************/
static const char *def_proxyhost = "127.0.0.1:443";
static const char *def_listenhost = "127.0.0.1:8080";
static int def_max_tunnels = 50;
static const char *def_cacert = NULL;
static const char *def_cert = NULL;
static const char *def_key = NULL;
static const char *def_dcert = NULL;
static const char *def_dkey = NULL;
static const char