tunala.h 7.88 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
/* 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);
void cb_ssl_info_set_output(FILE *fp); /* Called if output should be sent too */
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) */