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,
+ const char *dh_file, const char *dh_special, int tmp_rsa,
+ 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);
* 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);
+ const 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);
static const char *def_cipher_list = NULL;
static const char *def_dh_file = NULL;
static const char *def_dh_special = NULL;
+static int def_tmp_rsa = 1;
static int def_ctx_options = 0;
static int def_verify_mode = 0;
static unsigned int def_verify_depth = 10;
static int def_out_state = 0;
static unsigned int def_out_verify = 0;
static int def_out_totals = 0;
+static int def_out_conns = 0;
static const char *helpstring =
"\n'Tunala' (A tunneler with a New Zealand accent)\n"
" -cipher <list> (specifies cipher list to use)\n"
" -dh_file <path> (a PEM file containing DH parameters to use)\n"
" -dh_special <NULL|generate|standard> (see below: def=NULL)\n"
+" -no_tmp_rsa (don't generate temporary RSA keys)\n"
" -no_ssl2 (disable SSLv2)\n"
" -no_ssl3 (disable SSLv3)\n"
" -no_tls1 (disable TLSv1)\n"
" -v_strict (do not continue if peer doesn't authenticate)\n"
" -v_once (no verification in renegotiates)\n"
" -v_depth <num> (limit certificate chain depth, default = 10)\n"
+" -out_conns (prints client connections and disconnections)\n"
" -out_state (prints SSL handshake states)\n"
" -out_verify <0|1|2|3> (prints certificate verification states: def=1)\n"
" -out_totals (prints out byte-totals when a tunnel closes)\n"
static int parse_max_tunnels(const char *s, unsigned int *maxtunnels)
{
unsigned long l;
- char *temp;
- l = strtoul(s, &temp, 10);
- if((temp == s) || (*temp != '\0') || (l < 1) || (l > 1024)) {
+ if(!int_strtoul(s, &l) || (l < 1) || (l > 1024)) {
fprintf(stderr, "Error, '%s' is an invalid value for "
"maxtunnels\n", s);
return 0;
static int parse_server_mode(const char *s, int *servermode)
{
unsigned long l;
- char *temp;
- l = strtoul(s, &temp, 10);
- if((temp == s) || (*temp != '\0') || (l > 1)) {
+ if(!int_strtoul(s, &l) || (l > 1)) {
fprintf(stderr, "Error, '%s' is an invalid value for the "
"server mode\n", s);
return 0;
static int parse_verify_level(const char *s, unsigned int *verify_level)
{
unsigned long l;
- char *temp;
- l = strtoul(s, &temp, 10);
- if((temp == s) || (*temp != '\0') || (l > 3)) {
+ if(!int_strtoul(s, &l) || (l > 3)) {
fprintf(stderr, "Error, '%s' is an invalid value for "
"out_verify\n", s);
return 0;
static int parse_verify_depth(const char *s, unsigned int *verify_depth)
{
unsigned long l;
- char *temp;
- l = strtoul(s, &temp, 10);
- if((temp == s) || (*temp != '\0') || (l < 1) || (l > 50)) {
+ if(!int_strtoul(s, &l) || (l < 1) || (l > 50)) {
fprintf(stderr, "Error, '%s' is an invalid value for "
"verify_depth\n", s);
return 0;
}
/* Some fprintf format strings used when tunnels close */
-static const char *io_stats_client_dirty =
-" SSL (network) traffic to/from server; %8lu bytes in, %8lu bytes out\n";
-static const char *io_stats_client_clean =
-" tunnelled data to/from server; %8lu bytes in, %8lu bytes out\n";
-static const char *io_stats_server_dirty =
-" SSL (network) traffic to/from client; %8lu bytes in, %8lu bytes out\n";
-static const char *io_stats_server_clean =
-" tunnelled data to/from client; %8lu bytes in, %8lu bytes out\n";
+static const char *io_stats_dirty =
+" SSL traffic; %8lu bytes in, %8lu bytes out\n";
+static const char *io_stats_clean =
+" clear traffic; %8lu bytes in, %8lu bytes out\n";
int main(int argc, char *argv[])
{
int newfd;
tunala_world_t world;
tunala_item_t *t_item;
- unsigned char *proxy_ip;
+ const char *proxy_ip;
unsigned short proxy_port;
/* Overridables */
const char *proxyhost = def_proxyhost;
const char *cipher_list = def_cipher_list;
const char *dh_file = def_dh_file;
const char *dh_special = def_dh_special;
+ int tmp_rsa = def_tmp_rsa;
int ctx_options = def_ctx_options;
int verify_mode = def_verify_mode;
unsigned int verify_depth = def_verify_depth;
int out_state = def_out_state;
unsigned int out_verify = def_out_verify;
int out_totals = def_out_totals;
+ int out_conns = def_out_conns;
/* Parse command-line arguments */
next_arg:
if(!parse_dh_special(*argv, &dh_special))
return 1;
goto next_arg;
+ } else if(strcmp(*argv, "-no_tmp_rsa") == 0) {
+ tmp_rsa = 0;
+ goto next_arg;
} else if(strcmp(*argv, "-no_ssl2") == 0) {
ctx_options |= SSL_OP_NO_SSLv2;
goto next_arg;
} else if(strcmp(*argv, "-out_totals") == 0) {
out_totals = 1;
goto next_arg;
+ } else if(strcmp(*argv, "-out_conns") == 0) {
+ out_conns = 1;
+ goto next_arg;
} else if((strcmp(*argv, "-h") == 0) ||
(strcmp(*argv, "-help") == 0) ||
(strcmp(*argv, "-?") == 0)) {
} else
return usage(*argv, 1);
}
+ /* Run any sanity checks we want here */
+ if(!cert && !dcert && server_mode)
+ fprintf(stderr, "WARNING: you are running an SSL server without "
+ "a certificate - this may not work!\n");
/* Initialise network stuff */
if(!ip_initialise())
return err_str0("ip_initialise failed");
- err_str0("ip_initialise succeeded");
/* Create the SSL_CTX */
if((world.ssl_ctx = initialise_ssl_ctx(server_mode, engine_id,
cacert, cert, key, dcert, dkey, cipher_list, dh_file,
- dh_special, ctx_options, out_state, out_verify,
+ dh_special, tmp_rsa, ctx_options, out_state, out_verify,
verify_mode, verify_depth)) == NULL)
return err_str1("initialise_ssl_ctx(engine_id=%s) failed",
(engine_id == NULL) ? "NULL" : engine_id);
- err_str1("initialise_ssl_ctx(engine_id=%s) succeeded",
- (engine_id == NULL) ? "NULL" : engine_id);
+ if(engine_id)
+ fprintf(stderr, "Info, engine '%s' initialised\n", engine_id);
/* Create the listener */
if((world.listen_fd = ip_create_listener(listenhost)) == -1)
return err_str1("ip_create_listener(%s) failed", listenhost);
- err_str1("ip_create_listener(%s) succeeded", listenhost);
+ fprintf(stderr, "Info, listening on '%s'\n", listenhost);
if(!ip_parse_address(proxyhost, &proxy_ip, &proxy_port, 0))
return err_str1("ip_parse_address(%s) failed", proxyhost);
- err_str1("ip_parse_address(%s) succeeded", proxyhost);
- fprintf(stderr, "Info - proxying to %d.%d.%d.%d:%d\n",
+ fprintf(stderr, "Info, proxying to '%s' (%d.%d.%d.%d:%d)\n", proxyhost,
(int)proxy_ip[0], (int)proxy_ip[1],
(int)proxy_ip[2], (int)proxy_ip[3], (int)proxy_port);
- fprintf(stderr, "Info - set maxtunnels to %d\n", (int)max_tunnels);
- fprintf(stderr, "Info - set to operate as an SSL %s\n",
+ fprintf(stderr, "Info, set maxtunnels to %d\n", (int)max_tunnels);
+ fprintf(stderr, "Info, set to operate as an SSL %s\n",
(server_mode ? "server" : "client"));
/* Initialise the rest of the stuff */
world.tunnels_used = world.tunnels_size = 0;
/* Now do the select */
switch(selector_select(&world.selector)) {
case -1:
- fprintf(stderr, "selector_select returned a badness error.\n");
- abort();
+ if(errno != EINTR) {
+ fprintf(stderr, "selector_select returned a "
+ "badness error.\n");
+ goto shouldnt_happen;
+ }
+ fprintf(stderr, "Warn, selector interrupted by a signal\n");
+ goto main_loop;
case 0:
- fprintf(stderr, "Warn, selector_select returned 0 - signal??\n");
+ fprintf(stderr, "Warn, selector_select returned 0 - signal?""?\n");
goto main_loop;
default:
break;
if(!tunala_world_new_item(&world, newfd, proxy_ip,
proxy_port, flipped))
fprintf(stderr, "tunala_world_new_item failed\n");
- else
+ else if(out_conns)
fprintf(stderr, "Info, new tunnel opened, now up to "
"%d\n", world.tunnels_used);
}
goto skip_totals;
fprintf(stderr, "Tunnel closing, traffic stats follow\n");
/* Display the encrypted (over the network) stats */
- fprintf(stderr, (server_mode ? io_stats_server_dirty :
- io_stats_client_dirty),
+ fprintf(stderr, io_stats_dirty,
buffer_total_in(state_machine_get_buffer(
&t_item->sm,SM_DIRTY_IN)),
buffer_total_out(state_machine_get_buffer(
* *receive* is data sent *out* of the state_machine on
* its 'clean' side. Hence the apparent back-to-front
* OUT/IN mixup here :-) */
- fprintf(stderr, (server_mode ? io_stats_server_clean :
- io_stats_client_clean),
+ fprintf(stderr, io_stats_clean,
buffer_total_out(state_machine_get_buffer(
&t_item->sm,SM_CLEAN_OUT)),
buffer_total_in(state_machine_get_buffer(
&t_item->sm,SM_CLEAN_IN)));
skip_totals:
tunala_world_del_item(&world, loop);
- fprintf(stderr, "Info, tunnel closed, down to %d\n",
+ if(out_conns)
+ fprintf(stderr, "Info, tunnel closed, down to %d\n",
world.tunnels_used);
}
else {
}
goto main_loop;
/* Should never get here */
+shouldnt_happen:
abort();
return 1;
}
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,
+ const char *dh_file, const char *dh_special, int tmp_rsa,
+ int ctx_options, int out_state, int out_verify, int verify_mode,
unsigned int verify_depth)
{
- SSL_CTX *ctx, *ret = NULL;
+ SSL_CTX *ctx = NULL, *ret = NULL;
SSL_METHOD *meth;
ENGINE *e = NULL;
if(meth == NULL)
goto err;
if(engine_id) {
+ ENGINE_load_builtin_engines();
if((e = ENGINE_by_id(engine_id)) == NULL) {
fprintf(stderr, "Error obtaining '%s' engine, openssl "
"errors follow\n", engine_id);
/* dcert and dkey */
if((dcert || dkey) && !ctx_set_cert(ctx, dcert, dkey))
goto err;
+ /* temporary RSA key generation */
+ if(tmp_rsa)
+ SSL_CTX_set_tmp_rsa_callback(ctx, cb_generate_tmp_rsa);
/* cipher_list */
if(cipher_list) {
}
static int tunala_world_new_item(tunala_world_t *world, int fd,
- const unsigned char *ip, unsigned short port, int flipped)
+ const char *ip, unsigned short port, int flipped)
{
tunala_item_t *item;
int newfd;