You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
244 lines
8.6 KiB
244 lines
8.6 KiB
/* |
|
* 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 <stdlib.h> |
|
# ifndef NO_SYSTEM_H |
|
# include <string.h> |
|
# ifdef HAVE_UNISTD_H |
|
# include <unistd.h> |
|
# endif |
|
# ifdef HAVE_FCNTL_H |
|
# include <fcntl.h> |
|
# endif |
|
# ifdef HAVE_LIMITS_H |
|
# include <limits.h> |
|
# endif |
|
# include <netdb.h> |
|
# include <signal.h> |
|
# include <sys/socket.h> |
|
# include <sys/types.h> |
|
# include <netinet/in.h> |
|
# endif /* !defined(NO_SYSTEM_H) */ |
|
|
|
# ifndef NO_OPENSSL |
|
# include <openssl/err.h> |
|
# include <openssl/engine.h> |
|
# include <openssl/ssl.h> |
|
# 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) */
|
|
|