From beb23252a6125bbb69503dfab91014077d136779 Mon Sep 17 00:00:00 2001 From: Geoff Thorpe Date: Wed, 20 Dec 2000 19:30:19 +0000 Subject: [PATCH] Some minor changes to the "tunala" demo. * Seal off some buffer functions so that only the higher-level IO functions are exposed. * Using the above change to buffer, add support to tunala for displaying traffic totals when a tunnel closes. Useful in debugging and analysis - you get to see the total encrypted traffic versus the total tunneled traffic. This shows not only how much expansion your data suffers from SSL (a lot if you send/receive a few bytes at a time), but also the overhead of SSL handshaking relative to the payload sent through the tunnel. This is controlled by the "-out_totals" switch to tunala. * Fix and tweak some bits in the README. Eg. sample output of "-out_totals" from a tunnel client when tunneling a brief "telnet" session. Tunnel closing, traffic stats follow SSL (network) traffic to/from server; 7305 bytes in, 3475 bytes out tunnelled data to/from server; 4295 bytes in, 186 bytes out --- demos/tunala/README | 16 ++++++++------- demos/tunala/buffer.c | 46 ++++++++++++++++++++++++++++++++----------- demos/tunala/tunala.c | 37 ++++++++++++++++++++++++++++++++++ demos/tunala/tunala.h | 8 ++++++++ 4 files changed, 88 insertions(+), 19 deletions(-) diff --git a/demos/tunala/README b/demos/tunala/README index c59fd92bda..3f3a4097a7 100644 --- a/demos/tunala/README +++ b/demos/tunala/README @@ -137,8 +137,8 @@ Possible things include: * A few other things you can already do in s_client and s_server :-) - * Support (and control over) session resuming, particular when functioning as - an SSL client. + * Support (and control over) session resuming, particularly when functioning + as an SSL client. If you have a particular environment where this model might work to let you "do SSL" without having OpenSSL be aware of the transport, then you should find you @@ -184,15 +184,17 @@ Here is an example of how to use "tunala" ... First, it's assumed that OpenSSL has already built, and that you are building inside the ./demos/tunala/ directory. If not - please correct the paths and -flags inside the Makefile. +flags inside the Makefile. Likewise, if you want to tweak the building, it's +best to try and do so in the makefile (eg. removing the debug flags and adding +optimisation flags). Secondly, this code so far has only ever been built and run on Linux - network specifics are more than likely to create little glitches on other unixen, particularly Solaris in my experience. If you're not on Linux, please read the code wherever compilation flares up and try to make the necessary changes - usually the man-page associated with the relevant function is enough (eg. all -that AF_INET/PF_INET stuff, subtely different parameters to various IPv4-related -functions like socket(), bind(), fcntl(), etc). +that AF_INET/PF_INET stuff, subtlely different parameters to various +IPv4-related functions like socket(), bind(), fcntl(), etc). Thirdly, if you are Win32, you probably need to do some *major* rewriting of ip.c to stand a hope in hell. Good luck, and please mail me the diff if you do @@ -207,12 +209,12 @@ Rinse and repeat. Inside one console, try typing; (i) ./tunala -listen localhost:8080 -proxy localhost:8081 -cacert CA.pem \ - -cert A-client.pem + -cert A-client.pem -out_totals -v_peer -v_strict In another console, type; (ii) ./tunala -listen localhost:8081 -proxy localhost:23 -cacert CA.pem \ - -cert A-server.pem -server 1 + -cert A-server.pem -server 1 -out_totals -v_peer -v_strict Now if you open another console and "telnet localhost 8080", you should be tunneled through to the telnet service on your local machine. Feel free to diff --git a/demos/tunala/buffer.c b/demos/tunala/buffer.c index 2915f2c67b..8142c02281 100644 --- a/demos/tunala/buffer.c +++ b/demos/tunala/buffer.c @@ -5,12 +5,13 @@ void buffer_init(buffer_t *buf) { buf->used = 0; + buf->total_in = buf->total_out = 0; } void buffer_close(buffer_t *buf) { - /* Our data is static - nothing needs "release", just reset */ - buffer_init(buf); + /* Our data is static - nothing needs "release", just reset it */ + buf->used = 0; } /* Code these simple ones in compact form */ @@ -26,8 +27,16 @@ int buffer_empty(buffer_t *buf) { return (buf->used == 0 ? 1 : 0); } int buffer_notempty(buffer_t *buf) { return (buf->used > 0 ? 1 : 0); } - -unsigned int buffer_adddata(buffer_t *buf, const unsigned char *ptr, +unsigned long buffer_total_in(buffer_t *buf) { + return buf->total_in; } +unsigned long buffer_total_out(buffer_t *buf) { + return buf->total_out; } + +/* These 3 static (internal) functions don't adjust the "total" variables as + * it's not sure when they're called how it should be interpreted. Only the + * higher-level "buffer_[to|from]_[fd|SSL|BIO]" functions should alter these + * values. */ +static unsigned int buffer_adddata(buffer_t *buf, const unsigned char *ptr, unsigned int size) { unsigned int added = MAX_DATA_SIZE - buf->used; @@ -37,10 +46,11 @@ unsigned int buffer_adddata(buffer_t *buf, const unsigned char *ptr, return 0; memcpy(buf->data + buf->used, ptr, added); buf->used += added; + buf->total_in += added; return added; } -unsigned int buffer_takedata(buffer_t *buf, unsigned char *ptr, +static unsigned int buffer_takedata(buffer_t *buf, unsigned char *ptr, unsigned int size) { unsigned int taken = buf->used; @@ -57,7 +67,7 @@ unsigned int buffer_takedata(buffer_t *buf, unsigned char *ptr, return taken; } -unsigned int buffer_tobuffer(buffer_t *to, buffer_t *from, int cap) +static unsigned int buffer_tobuffer(buffer_t *to, buffer_t *from, int cap) { unsigned int moved, tomove = from->used; if((int)tomove > cap) @@ -80,8 +90,10 @@ int buffer_from_fd(buffer_t *buf, int fd) /* Shouldn't be called in this case! */ abort(); toread = read(fd, buf->data + buf->used, toread); - if(toread > 0) + if(toread > 0) { buf->used += toread; + buf->total_in += toread; + } return toread; } @@ -92,8 +104,10 @@ int buffer_to_fd(buffer_t *buf, int fd) /* Shouldn't be called in this case! */ abort(); towrite = write(fd, buf->data, towrite); - if(towrite > 0) + if(towrite > 0) { buffer_takedata(buf, NULL, towrite); + buf->total_out += towrite; + } return towrite; } @@ -138,8 +152,10 @@ void buffer_from_SSL(buffer_t *buf, SSL *ssl) if(!ssl || buffer_full(buf)) return; ret = SSL_read(ssl, buf->data + buf->used, buffer_unused(buf)); - if(ret > 0) + if(ret > 0) { buf->used += ret; + buf->total_in += ret; + } if(ret < 0) int_ssl_check(ssl, ret); } @@ -150,8 +166,10 @@ void buffer_to_SSL(buffer_t *buf, SSL *ssl) if(!ssl || buffer_empty(buf)) return; ret = SSL_write(ssl, buf->data, buf->used); - if(ret > 0) + if(ret > 0) { buffer_takedata(buf, NULL, ret); + buf->total_out += ret; + } if(ret < 0) int_ssl_check(ssl, ret); } @@ -162,8 +180,10 @@ void buffer_from_BIO(buffer_t *buf, BIO *bio) if(!bio || buffer_full(buf)) return; ret = BIO_read(bio, buf->data + buf->used, buffer_unused(buf)); - if(ret > 0) + if(ret > 0) { buf->used += ret; + buf->total_in += ret; + } } void buffer_to_BIO(buffer_t *buf, BIO *bio) @@ -172,8 +192,10 @@ void buffer_to_BIO(buffer_t *buf, BIO *bio) if(!bio || buffer_empty(buf)) return; ret = BIO_write(bio, buf->data, buf->used); - if(ret > 0) + if(ret > 0) { buffer_takedata(buf, NULL, ret); + buf->total_out += ret; + } } #endif /* !defined(NO_OPENSSL) */ diff --git a/demos/tunala/tunala.c b/demos/tunala/tunala.c index 2b3d65d98c..594f00a1dc 100644 --- a/demos/tunala/tunala.c +++ b/demos/tunala/tunala.c @@ -100,6 +100,7 @@ static int def_server_mode = 0; static const char *def_cipher_list = NULL; static int def_out_state = 0; static unsigned int def_out_verify = 0; +static int def_out_totals = 0; static int def_verify_mode = 0; static unsigned int def_verify_depth = 10; @@ -119,6 +120,7 @@ static const char *helpstring = " -cipher (specifies cipher list to use)\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" " -v_peer (verify the peer certificate)\n" " -v_strict (do not continue if peer doesn't authenticate)\n" " -v_once (no verification in renegotiates)\n" @@ -208,6 +210,16 @@ static int parse_verify_depth(const char *s, unsigned int *verify_depth) return 1; } +/* 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"; + int main(int argc, char *argv[]) { unsigned int loop; @@ -230,6 +242,7 @@ int main(int argc, char *argv[]) const char *cipher_list = def_cipher_list; int out_state = def_out_state; unsigned int out_verify = def_out_verify; + int out_totals = def_out_totals; int verify_mode = def_verify_mode; unsigned int verify_depth = def_verify_depth; @@ -330,6 +343,9 @@ next_arg: if(!parse_verify_level(*argv, &out_verify)) return 1; goto next_arg; + } else if(strcmp(*argv, "-out_totals") == 0) { + out_totals = 1; + goto next_arg; } else if(strcmp(*argv, "-v_peer") == 0) { verify_mode |= SSL_VERIFY_PEER; goto next_arg; @@ -427,6 +443,27 @@ main_loop: /* We're closing whether for reasons of an error or a * natural close. Don't increment loop or t_item because * the next item is moving to us! */ + if(!out_totals) + 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), + buffer_total_in(state_machine_get_buffer( + &t_item->sm,SM_DIRTY_IN)), + buffer_total_out(state_machine_get_buffer( + &t_item->sm,SM_DIRTY_OUT))); + /* Display the local (tunnelled) stats. NB: Data we + * *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), + 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", world.tunnels_used); diff --git a/demos/tunala/tunala.h b/demos/tunala/tunala.h index 7d4e35dc9c..9248e877e8 100644 --- a/demos/tunala/tunala.h +++ b/demos/tunala/tunala.h @@ -41,6 +41,9 @@ typedef struct _buffer_t { unsigned char data[MAX_DATA_SIZE]; unsigned int used; + /* Statistical values - counts the total number of bytes read in and + * read out (respectively) since "buffer_init()" */ + unsigned long total_in, total_out; } buffer_t; /* Initialise a buffer structure before use */ @@ -59,7 +62,11 @@ int buffer_full(buffer_t *buf); /* Boolean, is it full? */ int buffer_notfull(buffer_t *buf); /* Boolean, is it not full? */ int buffer_empty(buffer_t *buf); /* Boolean, is it empty? */ int buffer_notempty(buffer_t *buf); /* Boolean, is it not empty? */ +unsigned long buffer_total_in(buffer_t *buf); /* Total bytes written to buffer */ +unsigned long buffer_total_out(buffer_t *buf); /* Total bytes read from buffer */ +#if 0 /* Currently used only within buffer.c - better to expose only + * higher-level functions anyway */ /* Add data to the tail of the buffer, returns the amount that was actually * added (so, you need to check if return value is less than size) */ unsigned int buffer_adddata(buffer_t *buf, const unsigned char *ptr, @@ -76,6 +83,7 @@ unsigned int buffer_takedata(buffer_t *buf, unsigned char *ptr, * buffer. Return value is the amount moved. The amount moved can be restricted * to a maximum by specifying "cap" - setting it to -1 means no limit. */ unsigned int buffer_tobuffer(buffer_t *to, buffer_t *from, int cap); +#endif #ifndef NO_IP /* Read or write between a file-descriptor and a buffer */ -- 2.25.1