/* * Tunala ("Tunneler with a New Zealand accent") Written by Geoff Thorpe, * but endorsed/supported by noone. Please use this is if it's useful or * informative to you, but it's only here as a scratchpad for ideas about how * you might (or might not) program with OpenSSL. If you deploy this is in a * mission-critical environment, and have not read, understood, audited, and * modified this code to your satisfaction, and the result is that all hell * breaks loose and you are looking for a new employer, then it proves * nothing except perhaps that Darwinism is alive and well. Let's just say, * *I* don't use this in a mission-critical environment, so it would be * stupid for anyone to assume that it is solid and/or tested enough when * even its author doesn't place that much trust in it. You have been warned. * With thanks to Cryptographic Appliances, Inc. */ #ifndef _TUNALA_H # define _TUNALA_H /* pull in autoconf fluff */ # ifndef NO_CONFIG_H # include "config.h" # else /* * We don't have autoconf, we have to set all of these unless a tweaked * Makefile tells us not to ... */ /* headers */ # ifndef NO_HAVE_SELECT # define HAVE_SELECT # endif # ifndef NO_HAVE_SOCKET # define HAVE_SOCKET # endif # ifndef NO_HAVE_UNISTD_H # define HAVE_UNISTD_H # endif # ifndef NO_HAVE_FCNTL_H # define HAVE_FCNTL_H # endif # ifndef NO_HAVE_LIMITS_H # define HAVE_LIMITS_H # endif /* features */ # ifndef NO_HAVE_STRSTR # define HAVE_STRSTR # endif # ifndef NO_HAVE_STRTOUL # define HAVE_STRTOUL # endif # endif # if !defined(HAVE_SELECT) || !defined(HAVE_SOCKET) # error "can't build without some network basics like select() and socket()" # endif # include # ifndef NO_SYSTEM_H # include # ifdef HAVE_UNISTD_H # include # endif # ifdef HAVE_FCNTL_H # include # endif # ifdef HAVE_LIMITS_H # include # endif # include # include # include # include # include # endif /* !defined(NO_SYSTEM_H) */ # ifndef NO_OPENSSL # include # include # include # endif /* !defined(NO_OPENSSL) */ # ifndef OPENSSL_NO_BUFFER /* * This is the generic "buffer" type that is used when feeding the * state-machine. It's basically a FIFO with respect to the "adddata" & * "takedata" type functions that operate on it. */ # define MAX_DATA_SIZE 16384 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 */ void buffer_init(buffer_t * buf); /* * Cleanup a buffer structure - presently not needed, but if buffer_t is * converted to using dynamic allocation, this would be required - so should * be called to protect against an explosion of memory leaks later if the * change is made. */ void buffer_close(buffer_t * buf); /* Basic functions to manipulate buffers */ unsigned int buffer_used(buffer_t * buf); /* How much data in the buffer */ unsigned int buffer_unused(buffer_t * buf); /* How much space in the buffer */ 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, unsigned int size); /* * Take data from the front of the buffer (and scroll the rest forward). If * "ptr" is NULL, this just removes data off the front of the buffer. Return * value is the amount actually removed (can be less than size if the buffer * has too little data). */ unsigned int buffer_takedata(buffer_t * buf, unsigned char *ptr, unsigned int size); /* * Flushes as much data as possible out of the "from" buffer into the "to" * 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 */ int buffer_from_fd(buffer_t * buf, int fd); int buffer_to_fd(buffer_t * buf, int fd); # endif /* !defined(NO_IP) */ # ifndef NO_OPENSSL /* Read or write between an SSL or BIO and a buffer */ void buffer_from_SSL(buffer_t * buf, SSL *ssl); void buffer_to_SSL(buffer_t * buf, SSL *ssl); void buffer_from_BIO(buffer_t * buf, BIO *bio); void buffer_to_BIO(buffer_t * buf, BIO *bio); /* Callbacks */ void cb_ssl_info(const SSL *s, int where, int ret); /* Called if output should be sent too */ void cb_ssl_info_set_output(FILE *fp); int cb_ssl_verify(int ok, X509_STORE_CTX *ctx); void cb_ssl_verify_set_output(FILE *fp); void cb_ssl_verify_set_depth(unsigned int verify_depth); void cb_ssl_verify_set_level(unsigned int level); RSA *cb_generate_tmp_rsa(SSL *s, int is_export, int keylength); # endif /* !defined(NO_OPENSSL) */ # endif /* !defined(OPENSSL_NO_BUFFER) */ # ifndef NO_TUNALA # ifdef OPENSSL_NO_BUFFER # error "TUNALA section of tunala.h requires BUFFER support" # endif typedef struct _state_machine_t { SSL *ssl; BIO *bio_intossl; BIO *bio_fromssl; buffer_t clean_in, clean_out; buffer_t dirty_in, dirty_out; } state_machine_t; typedef enum { SM_CLEAN_IN, SM_CLEAN_OUT, SM_DIRTY_IN, SM_DIRTY_OUT } sm_buffer_t; void state_machine_init(state_machine_t * machine); void state_machine_close(state_machine_t * machine); buffer_t *state_machine_get_buffer(state_machine_t * machine, sm_buffer_t type); SSL *state_machine_get_SSL(state_machine_t * machine); int state_machine_set_SSL(state_machine_t * machine, SSL *ssl, int is_server); /* Performs the data-IO loop and returns zero if the machine should close */ int state_machine_churn(state_machine_t * machine); /* * Is used to handle closing conditions - namely when one side of the tunnel * has closed but the other should finish flushing. */ int state_machine_close_clean(state_machine_t * machine); int state_machine_close_dirty(state_machine_t * machine); # endif /* !defined(NO_TUNALA) */ # ifndef NO_IP /* * Initialise anything related to the networking. This includes blocking * pesky SIGPIPE signals. */ int ip_initialise(void); /* * ip is the 4-byte ip address (eg. 127.0.0.1 is {0x7F,0x00,0x00,0x01}), port * is the port to listen on (host byte order), and the return value is the * file-descriptor or -1 on error. */ int ip_create_listener_split(const char *ip, unsigned short port); /* Same semantics as above. */ int ip_create_connection_split(const char *ip, unsigned short port); /* Converts a string into the ip/port before calling the above */ int ip_create_listener(const char *address); int ip_create_connection(const char *address); /* * Just does a string conversion on its own. NB: If accept_all_ip is * non-zero, then the address string could be just a port. Ie. it's suitable * for a listening address but not a connecting address. */ int ip_parse_address(const char *address, const char **parsed_ip, unsigned short *port, int accept_all_ip); /* * Accepts an incoming connection through the listener. Assumes selects and * what-not have deemed it an appropriate thing to do. */ int ip_accept_connection(int listen_fd); # endif /* !defined(NO_IP) */ /* These functions wrap up things that can be portability hassles. */ int int_strtoul(const char *str, unsigned long *val); # ifdef HAVE_STRSTR # define int_strstr strstr # else char *int_strstr(const char *haystack, const char *needle); # endif #endif /* !defined(_TUNALA_H) */