summaryrefslogtreecommitdiffstats
path: root/demos/tunala/tunala.h
blob: 3a752f259a949bee636ad6574cd2cd1e570e7430 (plain)
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) */
OpenPOWER on IntegriCloud