1ebfedea0SLionel Sambuc #if defined(NO_BUFFER) || defined(NO_IP) || defined(NO_OPENSSL)
2ebfedea0SLionel Sambuc # error "Badness, NO_BUFFER, NO_IP or NO_OPENSSL is defined, turn them *off*"
3ebfedea0SLionel Sambuc #endif
4ebfedea0SLionel Sambuc
5ebfedea0SLionel Sambuc /* Include our bits'n'pieces */
6ebfedea0SLionel Sambuc #include "tunala.h"
7ebfedea0SLionel Sambuc
8ebfedea0SLionel Sambuc /********************************************/
9ebfedea0SLionel Sambuc /* Our local types that specify our "world" */
10ebfedea0SLionel Sambuc /********************************************/
11ebfedea0SLionel Sambuc
12*0a6a1f1dSLionel Sambuc /*
13*0a6a1f1dSLionel Sambuc * These represent running "tunnels". Eg. if you wanted to do SSL in a
14*0a6a1f1dSLionel Sambuc * "message-passing" scanario, the "int" file-descriptors might be replaced
15*0a6a1f1dSLionel Sambuc * by thread or process IDs, and the "select" code might be replaced by
16*0a6a1f1dSLionel Sambuc * message handling code. Whatever.
17*0a6a1f1dSLionel Sambuc */
18ebfedea0SLionel Sambuc typedef struct _tunala_item_t {
19*0a6a1f1dSLionel Sambuc /*
20*0a6a1f1dSLionel Sambuc * The underlying SSL state machine. This is a data-only processing unit
21*0a6a1f1dSLionel Sambuc * and we communicate with it by talking to its four "buffers".
22*0a6a1f1dSLionel Sambuc */
23ebfedea0SLionel Sambuc state_machine_t sm;
24*0a6a1f1dSLionel Sambuc /*
25*0a6a1f1dSLionel Sambuc * The file-descriptors for the "dirty" (encrypted) side of the SSL
26ebfedea0SLionel Sambuc * setup. In actuality, this is typically a socket and both values are
27*0a6a1f1dSLionel Sambuc * identical.
28*0a6a1f1dSLionel Sambuc */
29ebfedea0SLionel Sambuc int dirty_read, dirty_send;
30*0a6a1f1dSLionel Sambuc /*
31*0a6a1f1dSLionel Sambuc * The file-descriptors for the "clean" (unencrypted) side of the SSL
32ebfedea0SLionel Sambuc * setup. These could be stdin/stdout, a socket (both values the same),
33*0a6a1f1dSLionel Sambuc * or whatever you like.
34*0a6a1f1dSLionel Sambuc */
35ebfedea0SLionel Sambuc int clean_read, clean_send;
36ebfedea0SLionel Sambuc } tunala_item_t;
37ebfedea0SLionel Sambuc
38*0a6a1f1dSLionel Sambuc /*
39*0a6a1f1dSLionel Sambuc * This structure is used as the data for running the main loop. Namely, in a
40ebfedea0SLionel Sambuc * network format such as this, it is stuff for select() - but as pointed out,
41ebfedea0SLionel Sambuc * when moving the real-world to somewhere else, this might be replaced by
42ebfedea0SLionel Sambuc * something entirely different. It's basically the stuff that controls when
43*0a6a1f1dSLionel Sambuc * it's time to do some "work".
44*0a6a1f1dSLionel Sambuc */
45ebfedea0SLionel Sambuc typedef struct _select_sets_t {
46*0a6a1f1dSLionel Sambuc int max; /* As required as the first argument to
47*0a6a1f1dSLionel Sambuc * select() */
48ebfedea0SLionel Sambuc fd_set reads, sends, excepts; /* As passed to select() */
49ebfedea0SLionel Sambuc } select_sets_t;
50ebfedea0SLionel Sambuc typedef struct _tunala_selector_t {
51ebfedea0SLionel Sambuc select_sets_t last_selected; /* Results of the last select() */
52ebfedea0SLionel Sambuc select_sets_t next_select; /* What we'll next select on */
53ebfedea0SLionel Sambuc } tunala_selector_t;
54ebfedea0SLionel Sambuc
55*0a6a1f1dSLionel Sambuc /*
56*0a6a1f1dSLionel Sambuc * This structure is *everything*. We do it to avoid the use of globals so
57*0a6a1f1dSLionel Sambuc * that, for example, it would be easier to shift things around between
58*0a6a1f1dSLionel Sambuc * async-IO, thread-based, or multi-fork()ed (or combinations thereof).
59*0a6a1f1dSLionel Sambuc */
60ebfedea0SLionel Sambuc typedef struct _tunala_world_t {
61ebfedea0SLionel Sambuc /* The file-descriptor we "listen" on for new connections */
62ebfedea0SLionel Sambuc int listen_fd;
63ebfedea0SLionel Sambuc /* The array of tunnels */
64ebfedea0SLionel Sambuc tunala_item_t *tunnels;
65ebfedea0SLionel Sambuc /* the number of tunnels in use and allocated, respectively */
66ebfedea0SLionel Sambuc unsigned int tunnels_used, tunnels_size;
67ebfedea0SLionel Sambuc /* Our outside "loop" context stuff */
68ebfedea0SLionel Sambuc tunala_selector_t selector;
69*0a6a1f1dSLionel Sambuc /*
70*0a6a1f1dSLionel Sambuc * Our SSL_CTX, which is configured as the SSL client or server and has
71*0a6a1f1dSLionel Sambuc * the various cert-settings and callbacks configured.
72*0a6a1f1dSLionel Sambuc */
73ebfedea0SLionel Sambuc SSL_CTX *ssl_ctx;
74*0a6a1f1dSLionel Sambuc /*
75*0a6a1f1dSLionel Sambuc * Simple flag with complex logic :-) Indicates whether we're an SSL
76*0a6a1f1dSLionel Sambuc * server or an SSL client.
77*0a6a1f1dSLionel Sambuc */
78ebfedea0SLionel Sambuc int server_mode;
79ebfedea0SLionel Sambuc } tunala_world_t;
80ebfedea0SLionel Sambuc
81ebfedea0SLionel Sambuc /*****************************/
82ebfedea0SLionel Sambuc /* Internal static functions */
83ebfedea0SLionel Sambuc /*****************************/
84ebfedea0SLionel Sambuc
85ebfedea0SLionel Sambuc static SSL_CTX *initialise_ssl_ctx(int server_mode, const char *engine_id,
86*0a6a1f1dSLionel Sambuc const char *CAfile, const char *cert,
87*0a6a1f1dSLionel Sambuc const char *key, const char *dcert,
88*0a6a1f1dSLionel Sambuc const char *dkey, const char *cipher_list,
89*0a6a1f1dSLionel Sambuc const char *dh_file,
90*0a6a1f1dSLionel Sambuc const char *dh_special, int tmp_rsa,
91*0a6a1f1dSLionel Sambuc int ctx_options, int out_state,
92*0a6a1f1dSLionel Sambuc int out_verify, int verify_mode,
93ebfedea0SLionel Sambuc unsigned int verify_depth);
94ebfedea0SLionel Sambuc static void selector_init(tunala_selector_t * selector);
95ebfedea0SLionel Sambuc static void selector_add_listener(tunala_selector_t * selector, int fd);
96*0a6a1f1dSLionel Sambuc static void selector_add_tunala(tunala_selector_t * selector,
97*0a6a1f1dSLionel Sambuc tunala_item_t * t);
98ebfedea0SLionel Sambuc static int selector_select(tunala_selector_t * selector);
99*0a6a1f1dSLionel Sambuc /*
100*0a6a1f1dSLionel Sambuc * This returns -1 for error, 0 for no new connections, or 1 for success, in
101*0a6a1f1dSLionel Sambuc * which case *newfd is populated.
102*0a6a1f1dSLionel Sambuc */
103*0a6a1f1dSLionel Sambuc static int selector_get_listener(tunala_selector_t * selector, int fd,
104*0a6a1f1dSLionel Sambuc int *newfd);
105ebfedea0SLionel Sambuc static int tunala_world_new_item(tunala_world_t * world, int fd,
106*0a6a1f1dSLionel Sambuc const char *ip, unsigned short port,
107*0a6a1f1dSLionel Sambuc int flipped);
108ebfedea0SLionel Sambuc static void tunala_world_del_item(tunala_world_t * world, unsigned int idx);
109ebfedea0SLionel Sambuc static int tunala_item_io(tunala_selector_t * selector, tunala_item_t * item);
110ebfedea0SLionel Sambuc
111ebfedea0SLionel Sambuc /*********************************************/
112ebfedea0SLionel Sambuc /* MAIN FUNCTION (and its utility functions) */
113ebfedea0SLionel Sambuc /*********************************************/
114ebfedea0SLionel Sambuc
115ebfedea0SLionel Sambuc static const char *def_proxyhost = "127.0.0.1:443";
116ebfedea0SLionel Sambuc static const char *def_listenhost = "127.0.0.1:8080";
117ebfedea0SLionel Sambuc static int def_max_tunnels = 50;
118ebfedea0SLionel Sambuc static const char *def_cacert = NULL;
119ebfedea0SLionel Sambuc static const char *def_cert = NULL;
120ebfedea0SLionel Sambuc static const char *def_key = NULL;
121ebfedea0SLionel Sambuc static const char *def_dcert = NULL;
122ebfedea0SLionel Sambuc static const char *def_dkey = NULL;
123ebfedea0SLionel Sambuc static const char *def_engine_id = NULL;
124ebfedea0SLionel Sambuc static int def_server_mode = 0;
125ebfedea0SLionel Sambuc static int def_flipped = 0;
126ebfedea0SLionel Sambuc static const char *def_cipher_list = NULL;
127ebfedea0SLionel Sambuc static const char *def_dh_file = NULL;
128ebfedea0SLionel Sambuc static const char *def_dh_special = NULL;
129ebfedea0SLionel Sambuc static int def_tmp_rsa = 1;
130ebfedea0SLionel Sambuc static int def_ctx_options = 0;
131ebfedea0SLionel Sambuc static int def_verify_mode = 0;
132ebfedea0SLionel Sambuc static unsigned int def_verify_depth = 10;
133ebfedea0SLionel Sambuc static int def_out_state = 0;
134ebfedea0SLionel Sambuc static unsigned int def_out_verify = 0;
135ebfedea0SLionel Sambuc static int def_out_totals = 0;
136ebfedea0SLionel Sambuc static int def_out_conns = 0;
137ebfedea0SLionel Sambuc
138ebfedea0SLionel Sambuc static const char *helpstring =
139ebfedea0SLionel Sambuc "\n'Tunala' (A tunneler with a New Zealand accent)\n"
140ebfedea0SLionel Sambuc "Usage: tunala [options], where options are from;\n"
141ebfedea0SLionel Sambuc " -listen [host:]<port> (default = 127.0.0.1:8080)\n"
142ebfedea0SLionel Sambuc " -proxy <host>:<port> (default = 127.0.0.1:443)\n"
143ebfedea0SLionel Sambuc " -maxtunnels <num> (default = 50)\n"
144ebfedea0SLionel Sambuc " -cacert <path|NULL> (default = NULL)\n"
145ebfedea0SLionel Sambuc " -cert <path|NULL> (default = NULL)\n"
146ebfedea0SLionel Sambuc " -key <path|NULL> (default = whatever '-cert' is)\n"
147ebfedea0SLionel Sambuc " -dcert <path|NULL> (usually for DSA, default = NULL)\n"
148ebfedea0SLionel Sambuc " -dkey <path|NULL> (usually for DSA, default = whatever '-dcert' is)\n"
149ebfedea0SLionel Sambuc " -engine <id|NULL> (default = NULL)\n"
150ebfedea0SLionel Sambuc " -server <0|1> (default = 0, ie. an SSL client)\n"
151ebfedea0SLionel Sambuc " -flipped <0|1> (makes SSL servers be network clients, and vice versa)\n"
152ebfedea0SLionel Sambuc " -cipher <list> (specifies cipher list to use)\n"
153ebfedea0SLionel Sambuc " -dh_file <path> (a PEM file containing DH parameters to use)\n"
154ebfedea0SLionel Sambuc " -dh_special <NULL|generate|standard> (see below: def=NULL)\n"
155ebfedea0SLionel Sambuc " -no_tmp_rsa (don't generate temporary RSA keys)\n"
156ebfedea0SLionel Sambuc " -no_ssl2 (disable SSLv2)\n"
157ebfedea0SLionel Sambuc " -no_ssl3 (disable SSLv3)\n"
158ebfedea0SLionel Sambuc " -no_tls1 (disable TLSv1)\n"
159ebfedea0SLionel Sambuc " -v_peer (verify the peer certificate)\n"
160ebfedea0SLionel Sambuc " -v_strict (do not continue if peer doesn't authenticate)\n"
161ebfedea0SLionel Sambuc " -v_once (no verification in renegotiates)\n"
162ebfedea0SLionel Sambuc " -v_depth <num> (limit certificate chain depth, default = 10)\n"
163ebfedea0SLionel Sambuc " -out_conns (prints client connections and disconnections)\n"
164ebfedea0SLionel Sambuc " -out_state (prints SSL handshake states)\n"
165ebfedea0SLionel Sambuc " -out_verify <0|1|2|3> (prints certificate verification states: def=1)\n"
166ebfedea0SLionel Sambuc " -out_totals (prints out byte-totals when a tunnel closes)\n"
167ebfedea0SLionel Sambuc " -<h|help|?> (displays this help screen)\n"
168ebfedea0SLionel Sambuc "Notes:\n"
169ebfedea0SLionel Sambuc "(1) It is recommended to specify a cert+key when operating as an SSL server.\n"
170ebfedea0SLionel Sambuc " If you only specify '-cert', the same file must contain a matching\n"
171ebfedea0SLionel Sambuc " private key.\n"
172ebfedea0SLionel Sambuc "(2) Either dh_file or dh_special can be used to specify where DH parameters\n"
173ebfedea0SLionel Sambuc " will be obtained from (or '-dh_special NULL' for the default choice) but\n"
174ebfedea0SLionel Sambuc " you cannot specify both. For dh_special, 'generate' will create new DH\n"
175ebfedea0SLionel Sambuc " parameters on startup, and 'standard' will use embedded parameters\n"
176ebfedea0SLionel Sambuc " instead.\n"
177ebfedea0SLionel Sambuc "(3) Normally an ssl client connects to an ssl server - so that an 'ssl client\n"
178ebfedea0SLionel Sambuc " tunala' listens for 'clean' client connections and proxies ssl, and an\n"
179ebfedea0SLionel Sambuc " 'ssl server tunala' listens for ssl connections and proxies 'clean'. With\n"
180ebfedea0SLionel Sambuc " '-flipped 1', this behaviour is reversed so that an 'ssl server tunala'\n"
181ebfedea0SLionel Sambuc " listens for clean client connections and proxies ssl (but participating\n"
182ebfedea0SLionel Sambuc " as an ssl *server* in the SSL/TLS protocol), and an 'ssl client tunala'\n"
183ebfedea0SLionel Sambuc " listens for ssl connections (participating as an ssl *client* in the\n"
184ebfedea0SLionel Sambuc " SSL/TLS protocol) and proxies 'clean' to the end destination. This can\n"
185ebfedea0SLionel Sambuc " be useful for allowing network access to 'servers' where only the server\n"
186ebfedea0SLionel Sambuc " needs to authenticate the client (ie. the other way is not required).\n"
187ebfedea0SLionel Sambuc " Even with client and server authentication, this 'technique' mitigates\n"
188ebfedea0SLionel Sambuc " some DoS (denial-of-service) potential as it will be the network client\n"
189ebfedea0SLionel Sambuc " having to perform the first private key operation rather than the other\n"
190ebfedea0SLionel Sambuc " way round.\n"
191ebfedea0SLionel Sambuc "(4) The 'technique' used by setting '-flipped 1' is probably compatible with\n"
192ebfedea0SLionel Sambuc " absolutely nothing except another complimentary instance of 'tunala'\n"
193ebfedea0SLionel Sambuc " running with '-flipped 1'. :-)\n";
194ebfedea0SLionel Sambuc
195*0a6a1f1dSLionel Sambuc /*
196*0a6a1f1dSLionel Sambuc * Default DH parameters for use with "-dh_special standard" ... stolen
197*0a6a1f1dSLionel Sambuc * striaght from s_server.
198*0a6a1f1dSLionel Sambuc */
199ebfedea0SLionel Sambuc static unsigned char dh512_p[] = {
200ebfedea0SLionel Sambuc 0xDA, 0x58, 0x3C, 0x16, 0xD9, 0x85, 0x22, 0x89, 0xD0, 0xE4, 0xAF, 0x75,
201ebfedea0SLionel Sambuc 0x6F, 0x4C, 0xCA, 0x92, 0xDD, 0x4B, 0xE5, 0x33, 0xB8, 0x04, 0xFB, 0x0F,
202ebfedea0SLionel Sambuc 0xED, 0x94, 0xEF, 0x9C, 0x8A, 0x44, 0x03, 0xED, 0x57, 0x46, 0x50, 0xD3,
203ebfedea0SLionel Sambuc 0x69, 0x99, 0xDB, 0x29, 0xD7, 0x76, 0x27, 0x6B, 0xA2, 0xD3, 0xD4, 0x12,
204ebfedea0SLionel Sambuc 0xE2, 0x18, 0xF4, 0xDD, 0x1E, 0x08, 0x4C, 0xF6, 0xD8, 0x00, 0x3E, 0x7C,
205ebfedea0SLionel Sambuc 0x47, 0x74, 0xE8, 0x33,
206ebfedea0SLionel Sambuc };
207*0a6a1f1dSLionel Sambuc
208ebfedea0SLionel Sambuc static unsigned char dh512_g[] = {
209ebfedea0SLionel Sambuc 0x02,
210ebfedea0SLionel Sambuc };
211ebfedea0SLionel Sambuc
212*0a6a1f1dSLionel Sambuc /*
213*0a6a1f1dSLionel Sambuc * And the function that parses the above "standard" parameters, again,
214*0a6a1f1dSLionel Sambuc * straight out of s_server.
215*0a6a1f1dSLionel Sambuc */
get_dh512(void)216ebfedea0SLionel Sambuc static DH *get_dh512(void)
217ebfedea0SLionel Sambuc {
218ebfedea0SLionel Sambuc DH *dh = NULL;
219ebfedea0SLionel Sambuc
220*0a6a1f1dSLionel Sambuc if ((dh = DH_new()) == NULL)
221*0a6a1f1dSLionel Sambuc return (NULL);
222ebfedea0SLionel Sambuc dh->p = BN_bin2bn(dh512_p, sizeof(dh512_p), NULL);
223ebfedea0SLionel Sambuc dh->g = BN_bin2bn(dh512_g, sizeof(dh512_g), NULL);
224ebfedea0SLionel Sambuc if ((dh->p == NULL) || (dh->g == NULL))
225ebfedea0SLionel Sambuc return (NULL);
226ebfedea0SLionel Sambuc return (dh);
227ebfedea0SLionel Sambuc }
228ebfedea0SLionel Sambuc
229ebfedea0SLionel Sambuc /* Various help/error messages used by main() */
usage(const char * errstr,int isunknownarg)230ebfedea0SLionel Sambuc static int usage(const char *errstr, int isunknownarg)
231ebfedea0SLionel Sambuc {
232ebfedea0SLionel Sambuc if (isunknownarg)
233ebfedea0SLionel Sambuc fprintf(stderr, "Error: unknown argument '%s'\n", errstr);
234ebfedea0SLionel Sambuc else
235ebfedea0SLionel Sambuc fprintf(stderr, "Error: %s\n", errstr);
236ebfedea0SLionel Sambuc fprintf(stderr, "%s\n", helpstring);
237ebfedea0SLionel Sambuc return 1;
238ebfedea0SLionel Sambuc }
239ebfedea0SLionel Sambuc
err_str0(const char * str0)240ebfedea0SLionel Sambuc static int err_str0(const char *str0)
241ebfedea0SLionel Sambuc {
242ebfedea0SLionel Sambuc fprintf(stderr, "%s\n", str0);
243ebfedea0SLionel Sambuc return 1;
244ebfedea0SLionel Sambuc }
245ebfedea0SLionel Sambuc
err_str1(const char * fmt,const char * str1)246ebfedea0SLionel Sambuc static int err_str1(const char *fmt, const char *str1)
247ebfedea0SLionel Sambuc {
248ebfedea0SLionel Sambuc fprintf(stderr, fmt, str1);
249ebfedea0SLionel Sambuc fprintf(stderr, "\n");
250ebfedea0SLionel Sambuc return 1;
251ebfedea0SLionel Sambuc }
252ebfedea0SLionel Sambuc
parse_max_tunnels(const char * s,unsigned int * maxtunnels)253ebfedea0SLionel Sambuc static int parse_max_tunnels(const char *s, unsigned int *maxtunnels)
254ebfedea0SLionel Sambuc {
255ebfedea0SLionel Sambuc unsigned long l;
256ebfedea0SLionel Sambuc if (!int_strtoul(s, &l) || (l < 1) || (l > 1024)) {
257ebfedea0SLionel Sambuc fprintf(stderr, "Error, '%s' is an invalid value for "
258ebfedea0SLionel Sambuc "maxtunnels\n", s);
259ebfedea0SLionel Sambuc return 0;
260ebfedea0SLionel Sambuc }
261ebfedea0SLionel Sambuc *maxtunnels = (unsigned int)l;
262ebfedea0SLionel Sambuc return 1;
263ebfedea0SLionel Sambuc }
264ebfedea0SLionel Sambuc
parse_server_mode(const char * s,int * servermode)265ebfedea0SLionel Sambuc static int parse_server_mode(const char *s, int *servermode)
266ebfedea0SLionel Sambuc {
267ebfedea0SLionel Sambuc unsigned long l;
268ebfedea0SLionel Sambuc if (!int_strtoul(s, &l) || (l > 1)) {
269ebfedea0SLionel Sambuc fprintf(stderr, "Error, '%s' is an invalid value for the "
270ebfedea0SLionel Sambuc "server mode\n", s);
271ebfedea0SLionel Sambuc return 0;
272ebfedea0SLionel Sambuc }
273ebfedea0SLionel Sambuc *servermode = (int)l;
274ebfedea0SLionel Sambuc return 1;
275ebfedea0SLionel Sambuc }
276ebfedea0SLionel Sambuc
parse_dh_special(const char * s,const char ** dh_special)277ebfedea0SLionel Sambuc static int parse_dh_special(const char *s, const char **dh_special)
278ebfedea0SLionel Sambuc {
279ebfedea0SLionel Sambuc if ((strcmp(s, "NULL") == 0) || (strcmp(s, "generate") == 0) ||
280ebfedea0SLionel Sambuc (strcmp(s, "standard") == 0)) {
281ebfedea0SLionel Sambuc *dh_special = s;
282ebfedea0SLionel Sambuc return 1;
283ebfedea0SLionel Sambuc }
284ebfedea0SLionel Sambuc fprintf(stderr, "Error, '%s' is an invalid value for 'dh_special'\n", s);
285ebfedea0SLionel Sambuc return 0;
286ebfedea0SLionel Sambuc }
287ebfedea0SLionel Sambuc
parse_verify_level(const char * s,unsigned int * verify_level)288ebfedea0SLionel Sambuc static int parse_verify_level(const char *s, unsigned int *verify_level)
289ebfedea0SLionel Sambuc {
290ebfedea0SLionel Sambuc unsigned long l;
291ebfedea0SLionel Sambuc if (!int_strtoul(s, &l) || (l > 3)) {
292ebfedea0SLionel Sambuc fprintf(stderr, "Error, '%s' is an invalid value for "
293ebfedea0SLionel Sambuc "out_verify\n", s);
294ebfedea0SLionel Sambuc return 0;
295ebfedea0SLionel Sambuc }
296ebfedea0SLionel Sambuc *verify_level = (unsigned int)l;
297ebfedea0SLionel Sambuc return 1;
298ebfedea0SLionel Sambuc }
299ebfedea0SLionel Sambuc
parse_verify_depth(const char * s,unsigned int * verify_depth)300ebfedea0SLionel Sambuc static int parse_verify_depth(const char *s, unsigned int *verify_depth)
301ebfedea0SLionel Sambuc {
302ebfedea0SLionel Sambuc unsigned long l;
303ebfedea0SLionel Sambuc if (!int_strtoul(s, &l) || (l < 1) || (l > 50)) {
304ebfedea0SLionel Sambuc fprintf(stderr, "Error, '%s' is an invalid value for "
305ebfedea0SLionel Sambuc "verify_depth\n", s);
306ebfedea0SLionel Sambuc return 0;
307ebfedea0SLionel Sambuc }
308ebfedea0SLionel Sambuc *verify_depth = (unsigned int)l;
309ebfedea0SLionel Sambuc return 1;
310ebfedea0SLionel Sambuc }
311ebfedea0SLionel Sambuc
312ebfedea0SLionel Sambuc /* Some fprintf format strings used when tunnels close */
313ebfedea0SLionel Sambuc static const char *io_stats_dirty =
314ebfedea0SLionel Sambuc " SSL traffic; %8lu bytes in, %8lu bytes out\n";
315ebfedea0SLionel Sambuc static const char *io_stats_clean =
316ebfedea0SLionel Sambuc " clear traffic; %8lu bytes in, %8lu bytes out\n";
317ebfedea0SLionel Sambuc
main(int argc,char * argv[])318ebfedea0SLionel Sambuc int main(int argc, char *argv[])
319ebfedea0SLionel Sambuc {
320ebfedea0SLionel Sambuc unsigned int loop;
321ebfedea0SLionel Sambuc int newfd;
322ebfedea0SLionel Sambuc tunala_world_t world;
323ebfedea0SLionel Sambuc tunala_item_t *t_item;
324ebfedea0SLionel Sambuc const char *proxy_ip;
325ebfedea0SLionel Sambuc unsigned short proxy_port;
326ebfedea0SLionel Sambuc /* Overridables */
327ebfedea0SLionel Sambuc const char *proxyhost = def_proxyhost;
328ebfedea0SLionel Sambuc const char *listenhost = def_listenhost;
329ebfedea0SLionel Sambuc unsigned int max_tunnels = def_max_tunnels;
330ebfedea0SLionel Sambuc const char *cacert = def_cacert;
331ebfedea0SLionel Sambuc const char *cert = def_cert;
332ebfedea0SLionel Sambuc const char *key = def_key;
333ebfedea0SLionel Sambuc const char *dcert = def_dcert;
334ebfedea0SLionel Sambuc const char *dkey = def_dkey;
335ebfedea0SLionel Sambuc const char *engine_id = def_engine_id;
336ebfedea0SLionel Sambuc int server_mode = def_server_mode;
337ebfedea0SLionel Sambuc int flipped = def_flipped;
338ebfedea0SLionel Sambuc const char *cipher_list = def_cipher_list;
339ebfedea0SLionel Sambuc const char *dh_file = def_dh_file;
340ebfedea0SLionel Sambuc const char *dh_special = def_dh_special;
341ebfedea0SLionel Sambuc int tmp_rsa = def_tmp_rsa;
342ebfedea0SLionel Sambuc int ctx_options = def_ctx_options;
343ebfedea0SLionel Sambuc int verify_mode = def_verify_mode;
344ebfedea0SLionel Sambuc unsigned int verify_depth = def_verify_depth;
345ebfedea0SLionel Sambuc int out_state = def_out_state;
346ebfedea0SLionel Sambuc unsigned int out_verify = def_out_verify;
347ebfedea0SLionel Sambuc int out_totals = def_out_totals;
348ebfedea0SLionel Sambuc int out_conns = def_out_conns;
349ebfedea0SLionel Sambuc
350ebfedea0SLionel Sambuc /* Parse command-line arguments */
351ebfedea0SLionel Sambuc next_arg:
352*0a6a1f1dSLionel Sambuc argc--;
353*0a6a1f1dSLionel Sambuc argv++;
354ebfedea0SLionel Sambuc if (argc > 0) {
355ebfedea0SLionel Sambuc if (strcmp(*argv, "-listen") == 0) {
356ebfedea0SLionel Sambuc if (argc < 2)
357ebfedea0SLionel Sambuc return usage("-listen requires an argument", 0);
358*0a6a1f1dSLionel Sambuc argc--;
359*0a6a1f1dSLionel Sambuc argv++;
360ebfedea0SLionel Sambuc listenhost = *argv;
361ebfedea0SLionel Sambuc goto next_arg;
362ebfedea0SLionel Sambuc } else if (strcmp(*argv, "-proxy") == 0) {
363ebfedea0SLionel Sambuc if (argc < 2)
364ebfedea0SLionel Sambuc return usage("-proxy requires an argument", 0);
365*0a6a1f1dSLionel Sambuc argc--;
366*0a6a1f1dSLionel Sambuc argv++;
367ebfedea0SLionel Sambuc proxyhost = *argv;
368ebfedea0SLionel Sambuc goto next_arg;
369ebfedea0SLionel Sambuc } else if (strcmp(*argv, "-maxtunnels") == 0) {
370ebfedea0SLionel Sambuc if (argc < 2)
371ebfedea0SLionel Sambuc return usage("-maxtunnels requires an argument", 0);
372*0a6a1f1dSLionel Sambuc argc--;
373*0a6a1f1dSLionel Sambuc argv++;
374ebfedea0SLionel Sambuc if (!parse_max_tunnels(*argv, &max_tunnels))
375ebfedea0SLionel Sambuc return 1;
376ebfedea0SLionel Sambuc goto next_arg;
377ebfedea0SLionel Sambuc } else if (strcmp(*argv, "-cacert") == 0) {
378ebfedea0SLionel Sambuc if (argc < 2)
379ebfedea0SLionel Sambuc return usage("-cacert requires an argument", 0);
380*0a6a1f1dSLionel Sambuc argc--;
381*0a6a1f1dSLionel Sambuc argv++;
382ebfedea0SLionel Sambuc if (strcmp(*argv, "NULL") == 0)
383ebfedea0SLionel Sambuc cacert = NULL;
384ebfedea0SLionel Sambuc else
385ebfedea0SLionel Sambuc cacert = *argv;
386ebfedea0SLionel Sambuc goto next_arg;
387ebfedea0SLionel Sambuc } else if (strcmp(*argv, "-cert") == 0) {
388ebfedea0SLionel Sambuc if (argc < 2)
389ebfedea0SLionel Sambuc return usage("-cert requires an argument", 0);
390*0a6a1f1dSLionel Sambuc argc--;
391*0a6a1f1dSLionel Sambuc argv++;
392ebfedea0SLionel Sambuc if (strcmp(*argv, "NULL") == 0)
393ebfedea0SLionel Sambuc cert = NULL;
394ebfedea0SLionel Sambuc else
395ebfedea0SLionel Sambuc cert = *argv;
396ebfedea0SLionel Sambuc goto next_arg;
397ebfedea0SLionel Sambuc } else if (strcmp(*argv, "-key") == 0) {
398ebfedea0SLionel Sambuc if (argc < 2)
399ebfedea0SLionel Sambuc return usage("-key requires an argument", 0);
400*0a6a1f1dSLionel Sambuc argc--;
401*0a6a1f1dSLionel Sambuc argv++;
402ebfedea0SLionel Sambuc if (strcmp(*argv, "NULL") == 0)
403ebfedea0SLionel Sambuc key = NULL;
404ebfedea0SLionel Sambuc else
405ebfedea0SLionel Sambuc key = *argv;
406ebfedea0SLionel Sambuc goto next_arg;
407ebfedea0SLionel Sambuc } else if (strcmp(*argv, "-dcert") == 0) {
408ebfedea0SLionel Sambuc if (argc < 2)
409ebfedea0SLionel Sambuc return usage("-dcert requires an argument", 0);
410*0a6a1f1dSLionel Sambuc argc--;
411*0a6a1f1dSLionel Sambuc argv++;
412ebfedea0SLionel Sambuc if (strcmp(*argv, "NULL") == 0)
413ebfedea0SLionel Sambuc dcert = NULL;
414ebfedea0SLionel Sambuc else
415ebfedea0SLionel Sambuc dcert = *argv;
416ebfedea0SLionel Sambuc goto next_arg;
417ebfedea0SLionel Sambuc } else if (strcmp(*argv, "-dkey") == 0) {
418ebfedea0SLionel Sambuc if (argc < 2)
419ebfedea0SLionel Sambuc return usage("-dkey requires an argument", 0);
420*0a6a1f1dSLionel Sambuc argc--;
421*0a6a1f1dSLionel Sambuc argv++;
422ebfedea0SLionel Sambuc if (strcmp(*argv, "NULL") == 0)
423ebfedea0SLionel Sambuc dkey = NULL;
424ebfedea0SLionel Sambuc else
425ebfedea0SLionel Sambuc dkey = *argv;
426ebfedea0SLionel Sambuc goto next_arg;
427ebfedea0SLionel Sambuc } else if (strcmp(*argv, "-engine") == 0) {
428ebfedea0SLionel Sambuc if (argc < 2)
429ebfedea0SLionel Sambuc return usage("-engine requires an argument", 0);
430*0a6a1f1dSLionel Sambuc argc--;
431*0a6a1f1dSLionel Sambuc argv++;
432ebfedea0SLionel Sambuc engine_id = *argv;
433ebfedea0SLionel Sambuc goto next_arg;
434ebfedea0SLionel Sambuc } else if (strcmp(*argv, "-server") == 0) {
435ebfedea0SLionel Sambuc if (argc < 2)
436ebfedea0SLionel Sambuc return usage("-server requires an argument", 0);
437*0a6a1f1dSLionel Sambuc argc--;
438*0a6a1f1dSLionel Sambuc argv++;
439ebfedea0SLionel Sambuc if (!parse_server_mode(*argv, &server_mode))
440ebfedea0SLionel Sambuc return 1;
441ebfedea0SLionel Sambuc goto next_arg;
442ebfedea0SLionel Sambuc } else if (strcmp(*argv, "-flipped") == 0) {
443ebfedea0SLionel Sambuc if (argc < 2)
444ebfedea0SLionel Sambuc return usage("-flipped requires an argument", 0);
445*0a6a1f1dSLionel Sambuc argc--;
446*0a6a1f1dSLionel Sambuc argv++;
447ebfedea0SLionel Sambuc if (!parse_server_mode(*argv, &flipped))
448ebfedea0SLionel Sambuc return 1;
449ebfedea0SLionel Sambuc goto next_arg;
450ebfedea0SLionel Sambuc } else if (strcmp(*argv, "-cipher") == 0) {
451ebfedea0SLionel Sambuc if (argc < 2)
452ebfedea0SLionel Sambuc return usage("-cipher requires an argument", 0);
453*0a6a1f1dSLionel Sambuc argc--;
454*0a6a1f1dSLionel Sambuc argv++;
455ebfedea0SLionel Sambuc cipher_list = *argv;
456ebfedea0SLionel Sambuc goto next_arg;
457ebfedea0SLionel Sambuc } else if (strcmp(*argv, "-dh_file") == 0) {
458ebfedea0SLionel Sambuc if (argc < 2)
459ebfedea0SLionel Sambuc return usage("-dh_file requires an argument", 0);
460ebfedea0SLionel Sambuc if (dh_special)
461*0a6a1f1dSLionel Sambuc return usage("cannot mix -dh_file with " "-dh_special", 0);
462*0a6a1f1dSLionel Sambuc argc--;
463*0a6a1f1dSLionel Sambuc argv++;
464ebfedea0SLionel Sambuc dh_file = *argv;
465ebfedea0SLionel Sambuc goto next_arg;
466ebfedea0SLionel Sambuc } else if (strcmp(*argv, "-dh_special") == 0) {
467ebfedea0SLionel Sambuc if (argc < 2)
468ebfedea0SLionel Sambuc return usage("-dh_special requires an argument", 0);
469ebfedea0SLionel Sambuc if (dh_file)
470*0a6a1f1dSLionel Sambuc return usage("cannot mix -dh_file with " "-dh_special", 0);
471*0a6a1f1dSLionel Sambuc argc--;
472*0a6a1f1dSLionel Sambuc argv++;
473ebfedea0SLionel Sambuc if (!parse_dh_special(*argv, &dh_special))
474ebfedea0SLionel Sambuc return 1;
475ebfedea0SLionel Sambuc goto next_arg;
476ebfedea0SLionel Sambuc } else if (strcmp(*argv, "-no_tmp_rsa") == 0) {
477ebfedea0SLionel Sambuc tmp_rsa = 0;
478ebfedea0SLionel Sambuc goto next_arg;
479ebfedea0SLionel Sambuc } else if (strcmp(*argv, "-no_ssl2") == 0) {
480ebfedea0SLionel Sambuc ctx_options |= SSL_OP_NO_SSLv2;
481ebfedea0SLionel Sambuc goto next_arg;
482ebfedea0SLionel Sambuc } else if (strcmp(*argv, "-no_ssl3") == 0) {
483ebfedea0SLionel Sambuc ctx_options |= SSL_OP_NO_SSLv3;
484ebfedea0SLionel Sambuc goto next_arg;
485ebfedea0SLionel Sambuc } else if (strcmp(*argv, "-no_tls1") == 0) {
486ebfedea0SLionel Sambuc ctx_options |= SSL_OP_NO_TLSv1;
487ebfedea0SLionel Sambuc goto next_arg;
488ebfedea0SLionel Sambuc } else if (strcmp(*argv, "-v_peer") == 0) {
489ebfedea0SLionel Sambuc verify_mode |= SSL_VERIFY_PEER;
490ebfedea0SLionel Sambuc goto next_arg;
491ebfedea0SLionel Sambuc } else if (strcmp(*argv, "-v_strict") == 0) {
492ebfedea0SLionel Sambuc verify_mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
493ebfedea0SLionel Sambuc goto next_arg;
494ebfedea0SLionel Sambuc } else if (strcmp(*argv, "-v_once") == 0) {
495ebfedea0SLionel Sambuc verify_mode |= SSL_VERIFY_CLIENT_ONCE;
496ebfedea0SLionel Sambuc goto next_arg;
497ebfedea0SLionel Sambuc } else if (strcmp(*argv, "-v_depth") == 0) {
498ebfedea0SLionel Sambuc if (argc < 2)
499ebfedea0SLionel Sambuc return usage("-v_depth requires an argument", 0);
500*0a6a1f1dSLionel Sambuc argc--;
501*0a6a1f1dSLionel Sambuc argv++;
502ebfedea0SLionel Sambuc if (!parse_verify_depth(*argv, &verify_depth))
503ebfedea0SLionel Sambuc return 1;
504ebfedea0SLionel Sambuc goto next_arg;
505ebfedea0SLionel Sambuc } else if (strcmp(*argv, "-out_state") == 0) {
506ebfedea0SLionel Sambuc out_state = 1;
507ebfedea0SLionel Sambuc goto next_arg;
508ebfedea0SLionel Sambuc } else if (strcmp(*argv, "-out_verify") == 0) {
509ebfedea0SLionel Sambuc if (argc < 2)
510ebfedea0SLionel Sambuc return usage("-out_verify requires an argument", 0);
511*0a6a1f1dSLionel Sambuc argc--;
512*0a6a1f1dSLionel Sambuc argv++;
513ebfedea0SLionel Sambuc if (!parse_verify_level(*argv, &out_verify))
514ebfedea0SLionel Sambuc return 1;
515ebfedea0SLionel Sambuc goto next_arg;
516ebfedea0SLionel Sambuc } else if (strcmp(*argv, "-out_totals") == 0) {
517ebfedea0SLionel Sambuc out_totals = 1;
518ebfedea0SLionel Sambuc goto next_arg;
519ebfedea0SLionel Sambuc } else if (strcmp(*argv, "-out_conns") == 0) {
520ebfedea0SLionel Sambuc out_conns = 1;
521ebfedea0SLionel Sambuc goto next_arg;
522ebfedea0SLionel Sambuc } else if ((strcmp(*argv, "-h") == 0) ||
523ebfedea0SLionel Sambuc (strcmp(*argv, "-help") == 0) ||
524ebfedea0SLionel Sambuc (strcmp(*argv, "-?") == 0)) {
525ebfedea0SLionel Sambuc fprintf(stderr, "%s\n", helpstring);
526ebfedea0SLionel Sambuc return 0;
527ebfedea0SLionel Sambuc } else
528ebfedea0SLionel Sambuc return usage(*argv, 1);
529ebfedea0SLionel Sambuc }
530ebfedea0SLionel Sambuc /* Run any sanity checks we want here */
531ebfedea0SLionel Sambuc if (!cert && !dcert && server_mode)
532ebfedea0SLionel Sambuc fprintf(stderr, "WARNING: you are running an SSL server without "
533ebfedea0SLionel Sambuc "a certificate - this may not work!\n");
534ebfedea0SLionel Sambuc
535ebfedea0SLionel Sambuc /* Initialise network stuff */
536ebfedea0SLionel Sambuc if (!ip_initialise())
537ebfedea0SLionel Sambuc return err_str0("ip_initialise failed");
538ebfedea0SLionel Sambuc /* Create the SSL_CTX */
539ebfedea0SLionel Sambuc if ((world.ssl_ctx = initialise_ssl_ctx(server_mode, engine_id,
540*0a6a1f1dSLionel Sambuc cacert, cert, key, dcert, dkey,
541*0a6a1f1dSLionel Sambuc cipher_list, dh_file, dh_special,
542*0a6a1f1dSLionel Sambuc tmp_rsa, ctx_options, out_state,
543*0a6a1f1dSLionel Sambuc out_verify, verify_mode,
544*0a6a1f1dSLionel Sambuc verify_depth)) == NULL)
545ebfedea0SLionel Sambuc return err_str1("initialise_ssl_ctx(engine_id=%s) failed",
546ebfedea0SLionel Sambuc (engine_id == NULL) ? "NULL" : engine_id);
547ebfedea0SLionel Sambuc if (engine_id)
548ebfedea0SLionel Sambuc fprintf(stderr, "Info, engine '%s' initialised\n", engine_id);
549ebfedea0SLionel Sambuc /* Create the listener */
550ebfedea0SLionel Sambuc if ((world.listen_fd = ip_create_listener(listenhost)) == -1)
551ebfedea0SLionel Sambuc return err_str1("ip_create_listener(%s) failed", listenhost);
552ebfedea0SLionel Sambuc fprintf(stderr, "Info, listening on '%s'\n", listenhost);
553ebfedea0SLionel Sambuc if (!ip_parse_address(proxyhost, &proxy_ip, &proxy_port, 0))
554ebfedea0SLionel Sambuc return err_str1("ip_parse_address(%s) failed", proxyhost);
555ebfedea0SLionel Sambuc fprintf(stderr, "Info, proxying to '%s' (%d.%d.%d.%d:%d)\n", proxyhost,
556ebfedea0SLionel Sambuc (int)proxy_ip[0], (int)proxy_ip[1],
557ebfedea0SLionel Sambuc (int)proxy_ip[2], (int)proxy_ip[3], (int)proxy_port);
558ebfedea0SLionel Sambuc fprintf(stderr, "Info, set maxtunnels to %d\n", (int)max_tunnels);
559ebfedea0SLionel Sambuc fprintf(stderr, "Info, set to operate as an SSL %s\n",
560ebfedea0SLionel Sambuc (server_mode ? "server" : "client"));
561ebfedea0SLionel Sambuc /* Initialise the rest of the stuff */
562ebfedea0SLionel Sambuc world.tunnels_used = world.tunnels_size = 0;
563ebfedea0SLionel Sambuc world.tunnels = NULL;
564ebfedea0SLionel Sambuc world.server_mode = server_mode;
565ebfedea0SLionel Sambuc selector_init(&world.selector);
566ebfedea0SLionel Sambuc
567ebfedea0SLionel Sambuc /* We're ready to loop */
568ebfedea0SLionel Sambuc main_loop:
569ebfedea0SLionel Sambuc /* Should we listen for *new* tunnels? */
570ebfedea0SLionel Sambuc if (world.tunnels_used < max_tunnels)
571ebfedea0SLionel Sambuc selector_add_listener(&world.selector, world.listen_fd);
572ebfedea0SLionel Sambuc /* We should add in our existing tunnels */
573ebfedea0SLionel Sambuc for (loop = 0; loop < world.tunnels_used; loop++)
574ebfedea0SLionel Sambuc selector_add_tunala(&world.selector, world.tunnels + loop);
575ebfedea0SLionel Sambuc /* Now do the select */
576ebfedea0SLionel Sambuc switch (selector_select(&world.selector)) {
577ebfedea0SLionel Sambuc case -1:
578ebfedea0SLionel Sambuc if (errno != EINTR) {
579*0a6a1f1dSLionel Sambuc fprintf(stderr, "selector_select returned a " "badness error.\n");
580ebfedea0SLionel Sambuc goto shouldnt_happen;
581ebfedea0SLionel Sambuc }
582ebfedea0SLionel Sambuc fprintf(stderr, "Warn, selector interrupted by a signal\n");
583ebfedea0SLionel Sambuc goto main_loop;
584ebfedea0SLionel Sambuc case 0:
585ebfedea0SLionel Sambuc fprintf(stderr, "Warn, selector_select returned 0 - signal?" "?\n");
586ebfedea0SLionel Sambuc goto main_loop;
587ebfedea0SLionel Sambuc default:
588ebfedea0SLionel Sambuc break;
589ebfedea0SLionel Sambuc }
590ebfedea0SLionel Sambuc /* Accept new connection if we should and can */
591*0a6a1f1dSLionel Sambuc if ((world.tunnels_used < max_tunnels)
592*0a6a1f1dSLionel Sambuc && (selector_get_listener(&world.selector, world.listen_fd, &newfd) ==
593*0a6a1f1dSLionel Sambuc 1)) {
594ebfedea0SLionel Sambuc /* We have a new connection */
595ebfedea0SLionel Sambuc if (!tunala_world_new_item(&world, newfd, proxy_ip,
596ebfedea0SLionel Sambuc proxy_port, flipped))
597ebfedea0SLionel Sambuc fprintf(stderr, "tunala_world_new_item failed\n");
598ebfedea0SLionel Sambuc else if (out_conns)
599ebfedea0SLionel Sambuc fprintf(stderr, "Info, new tunnel opened, now up to "
600ebfedea0SLionel Sambuc "%d\n", world.tunnels_used);
601ebfedea0SLionel Sambuc }
602*0a6a1f1dSLionel Sambuc /*
603*0a6a1f1dSLionel Sambuc * Give each tunnel its moment, note the while loop is because it makes
604ebfedea0SLionel Sambuc * the logic easier than with "for" to deal with an array that may shift
605*0a6a1f1dSLionel Sambuc * because of deletes.
606*0a6a1f1dSLionel Sambuc */
607ebfedea0SLionel Sambuc loop = 0;
608ebfedea0SLionel Sambuc t_item = world.tunnels;
609ebfedea0SLionel Sambuc while (loop < world.tunnels_used) {
610ebfedea0SLionel Sambuc if (!tunala_item_io(&world.selector, t_item)) {
611*0a6a1f1dSLionel Sambuc /*
612*0a6a1f1dSLionel Sambuc * We're closing whether for reasons of an error or a natural
613*0a6a1f1dSLionel Sambuc * close. Don't increment loop or t_item because the next item is
614*0a6a1f1dSLionel Sambuc * moving to us!
615*0a6a1f1dSLionel Sambuc */
616ebfedea0SLionel Sambuc if (!out_totals)
617ebfedea0SLionel Sambuc goto skip_totals;
618ebfedea0SLionel Sambuc fprintf(stderr, "Tunnel closing, traffic stats follow\n");
619ebfedea0SLionel Sambuc /* Display the encrypted (over the network) stats */
620ebfedea0SLionel Sambuc fprintf(stderr, io_stats_dirty,
621*0a6a1f1dSLionel Sambuc buffer_total_in(state_machine_get_buffer
622*0a6a1f1dSLionel Sambuc (&t_item->sm, SM_DIRTY_IN)),
623*0a6a1f1dSLionel Sambuc buffer_total_out(state_machine_get_buffer
624*0a6a1f1dSLionel Sambuc (&t_item->sm, SM_DIRTY_OUT)));
625*0a6a1f1dSLionel Sambuc /*
626*0a6a1f1dSLionel Sambuc * Display the local (tunnelled) stats. NB: Data we *receive* is
627*0a6a1f1dSLionel Sambuc * data sent *out* of the state_machine on its 'clean' side.
628*0a6a1f1dSLionel Sambuc * Hence the apparent back-to-front OUT/IN mixup here :-)
629*0a6a1f1dSLionel Sambuc */
630ebfedea0SLionel Sambuc fprintf(stderr, io_stats_clean,
631*0a6a1f1dSLionel Sambuc buffer_total_out(state_machine_get_buffer
632*0a6a1f1dSLionel Sambuc (&t_item->sm, SM_CLEAN_OUT)),
633*0a6a1f1dSLionel Sambuc buffer_total_in(state_machine_get_buffer
634*0a6a1f1dSLionel Sambuc (&t_item->sm, SM_CLEAN_IN)));
635ebfedea0SLionel Sambuc skip_totals:
636ebfedea0SLionel Sambuc tunala_world_del_item(&world, loop);
637ebfedea0SLionel Sambuc if (out_conns)
638ebfedea0SLionel Sambuc fprintf(stderr, "Info, tunnel closed, down to %d\n",
639ebfedea0SLionel Sambuc world.tunnels_used);
640*0a6a1f1dSLionel Sambuc } else {
641ebfedea0SLionel Sambuc /* Move to the next item */
642ebfedea0SLionel Sambuc loop++;
643ebfedea0SLionel Sambuc t_item++;
644ebfedea0SLionel Sambuc }
645ebfedea0SLionel Sambuc }
646ebfedea0SLionel Sambuc goto main_loop;
647ebfedea0SLionel Sambuc /* Should never get here */
648ebfedea0SLionel Sambuc shouldnt_happen:
649ebfedea0SLionel Sambuc abort();
650ebfedea0SLionel Sambuc return 1;
651ebfedea0SLionel Sambuc }
652ebfedea0SLionel Sambuc
653ebfedea0SLionel Sambuc /****************/
654ebfedea0SLionel Sambuc /* OpenSSL bits */
655ebfedea0SLionel Sambuc /****************/
656ebfedea0SLionel Sambuc
ctx_set_cert(SSL_CTX * ctx,const char * cert,const char * key)657ebfedea0SLionel Sambuc static int ctx_set_cert(SSL_CTX *ctx, const char *cert, const char *key)
658ebfedea0SLionel Sambuc {
659ebfedea0SLionel Sambuc FILE *fp = NULL;
660ebfedea0SLionel Sambuc X509 *x509 = NULL;
661ebfedea0SLionel Sambuc EVP_PKEY *pkey = NULL;
662ebfedea0SLionel Sambuc int toret = 0; /* Assume an error */
663ebfedea0SLionel Sambuc
664ebfedea0SLionel Sambuc /* cert */
665ebfedea0SLionel Sambuc if (cert) {
666ebfedea0SLionel Sambuc if ((fp = fopen(cert, "r")) == NULL) {
667ebfedea0SLionel Sambuc fprintf(stderr, "Error opening cert file '%s'\n", cert);
668ebfedea0SLionel Sambuc goto err;
669ebfedea0SLionel Sambuc }
670ebfedea0SLionel Sambuc if (!PEM_read_X509(fp, &x509, NULL, NULL)) {
671*0a6a1f1dSLionel Sambuc fprintf(stderr, "Error reading PEM cert from '%s'\n", cert);
672ebfedea0SLionel Sambuc goto err;
673ebfedea0SLionel Sambuc }
674ebfedea0SLionel Sambuc if (!SSL_CTX_use_certificate(ctx, x509)) {
675*0a6a1f1dSLionel Sambuc fprintf(stderr, "Error, cert in '%s' can not be used\n", cert);
676ebfedea0SLionel Sambuc goto err;
677ebfedea0SLionel Sambuc }
678ebfedea0SLionel Sambuc /* Clear the FILE* for reuse in the "key" code */
679ebfedea0SLionel Sambuc fclose(fp);
680ebfedea0SLionel Sambuc fp = NULL;
681ebfedea0SLionel Sambuc fprintf(stderr, "Info, operating with cert in '%s'\n", cert);
682*0a6a1f1dSLionel Sambuc /*
683*0a6a1f1dSLionel Sambuc * If a cert was given without matching key, we assume the same file
684*0a6a1f1dSLionel Sambuc * contains the required key.
685*0a6a1f1dSLionel Sambuc */
686ebfedea0SLionel Sambuc if (!key)
687ebfedea0SLionel Sambuc key = cert;
688ebfedea0SLionel Sambuc } else {
689ebfedea0SLionel Sambuc if (key)
690ebfedea0SLionel Sambuc fprintf(stderr, "Error, can't specify a key without a "
691ebfedea0SLionel Sambuc "corresponding certificate\n");
692ebfedea0SLionel Sambuc else
693*0a6a1f1dSLionel Sambuc fprintf(stderr, "Error, ctx_set_cert called with " "NULLs!\n");
694ebfedea0SLionel Sambuc goto err;
695ebfedea0SLionel Sambuc }
696ebfedea0SLionel Sambuc /* key */
697ebfedea0SLionel Sambuc if (key) {
698ebfedea0SLionel Sambuc if ((fp = fopen(key, "r")) == NULL) {
699ebfedea0SLionel Sambuc fprintf(stderr, "Error opening key file '%s'\n", key);
700ebfedea0SLionel Sambuc goto err;
701ebfedea0SLionel Sambuc }
702ebfedea0SLionel Sambuc if (!PEM_read_PrivateKey(fp, &pkey, NULL, NULL)) {
703*0a6a1f1dSLionel Sambuc fprintf(stderr, "Error reading PEM key from '%s'\n", key);
704ebfedea0SLionel Sambuc goto err;
705ebfedea0SLionel Sambuc }
706ebfedea0SLionel Sambuc if (!SSL_CTX_use_PrivateKey(ctx, pkey)) {
707*0a6a1f1dSLionel Sambuc fprintf(stderr, "Error, key in '%s' can not be used\n", key);
708ebfedea0SLionel Sambuc goto err;
709ebfedea0SLionel Sambuc }
710ebfedea0SLionel Sambuc fprintf(stderr, "Info, operating with key in '%s'\n", key);
711ebfedea0SLionel Sambuc } else
712ebfedea0SLionel Sambuc fprintf(stderr, "Info, operating without a cert or key\n");
713ebfedea0SLionel Sambuc /* Success */
714*0a6a1f1dSLionel Sambuc toret = 1;
715*0a6a1f1dSLionel Sambuc err:
716ebfedea0SLionel Sambuc if (x509)
717ebfedea0SLionel Sambuc X509_free(x509);
718ebfedea0SLionel Sambuc if (pkey)
719ebfedea0SLionel Sambuc EVP_PKEY_free(pkey);
720ebfedea0SLionel Sambuc if (fp)
721ebfedea0SLionel Sambuc fclose(fp);
722ebfedea0SLionel Sambuc return toret;
723ebfedea0SLionel Sambuc }
724ebfedea0SLionel Sambuc
ctx_set_dh(SSL_CTX * ctx,const char * dh_file,const char * dh_special)725*0a6a1f1dSLionel Sambuc static int ctx_set_dh(SSL_CTX *ctx, const char *dh_file,
726*0a6a1f1dSLionel Sambuc const char *dh_special)
727ebfedea0SLionel Sambuc {
728ebfedea0SLionel Sambuc DH *dh = NULL;
729ebfedea0SLionel Sambuc FILE *fp = NULL;
730ebfedea0SLionel Sambuc
731ebfedea0SLionel Sambuc if (dh_special) {
732ebfedea0SLionel Sambuc if (strcmp(dh_special, "NULL") == 0)
733ebfedea0SLionel Sambuc return 1;
734ebfedea0SLionel Sambuc if (strcmp(dh_special, "standard") == 0) {
735ebfedea0SLionel Sambuc if ((dh = get_dh512()) == NULL) {
736ebfedea0SLionel Sambuc fprintf(stderr, "Error, can't parse 'standard'"
737ebfedea0SLionel Sambuc " DH parameters\n");
738ebfedea0SLionel Sambuc return 0;
739ebfedea0SLionel Sambuc }
740ebfedea0SLionel Sambuc fprintf(stderr, "Info, using 'standard' DH parameters\n");
741ebfedea0SLionel Sambuc goto do_it;
742ebfedea0SLionel Sambuc }
743ebfedea0SLionel Sambuc if (strcmp(dh_special, "generate") != 0)
744*0a6a1f1dSLionel Sambuc /*
745*0a6a1f1dSLionel Sambuc * This shouldn't happen - screening values is handled in main().
746*0a6a1f1dSLionel Sambuc */
747ebfedea0SLionel Sambuc abort();
748ebfedea0SLionel Sambuc fprintf(stderr, "Info, generating DH parameters ... ");
749ebfedea0SLionel Sambuc fflush(stderr);
750ebfedea0SLionel Sambuc if (!(dh = DH_new()) || !DH_generate_parameters_ex(dh, 512,
751*0a6a1f1dSLionel Sambuc DH_GENERATOR_5,
752*0a6a1f1dSLionel Sambuc NULL)) {
753ebfedea0SLionel Sambuc fprintf(stderr, "error!\n");
754ebfedea0SLionel Sambuc if (dh)
755ebfedea0SLionel Sambuc DH_free(dh);
756ebfedea0SLionel Sambuc return 0;
757ebfedea0SLionel Sambuc }
758ebfedea0SLionel Sambuc fprintf(stderr, "complete\n");
759ebfedea0SLionel Sambuc goto do_it;
760ebfedea0SLionel Sambuc }
761ebfedea0SLionel Sambuc /* So, we're loading dh_file */
762ebfedea0SLionel Sambuc if ((fp = fopen(dh_file, "r")) == NULL) {
763ebfedea0SLionel Sambuc fprintf(stderr, "Error, couldn't open '%s' for DH parameters\n",
764ebfedea0SLionel Sambuc dh_file);
765ebfedea0SLionel Sambuc return 0;
766ebfedea0SLionel Sambuc }
767ebfedea0SLionel Sambuc dh = PEM_read_DHparams(fp, NULL, NULL, NULL);
768ebfedea0SLionel Sambuc fclose(fp);
769ebfedea0SLionel Sambuc if (dh == NULL) {
770ebfedea0SLionel Sambuc fprintf(stderr, "Error, could not parse DH parameters from '%s'\n",
771ebfedea0SLionel Sambuc dh_file);
772ebfedea0SLionel Sambuc return 0;
773ebfedea0SLionel Sambuc }
774ebfedea0SLionel Sambuc fprintf(stderr, "Info, using DH parameters from file '%s'\n", dh_file);
775ebfedea0SLionel Sambuc do_it:
776ebfedea0SLionel Sambuc SSL_CTX_set_tmp_dh(ctx, dh);
777ebfedea0SLionel Sambuc DH_free(dh);
778ebfedea0SLionel Sambuc return 1;
779ebfedea0SLionel Sambuc }
780ebfedea0SLionel Sambuc
initialise_ssl_ctx(int server_mode,const char * engine_id,const char * CAfile,const char * cert,const char * key,const char * dcert,const char * dkey,const char * cipher_list,const char * dh_file,const char * dh_special,int tmp_rsa,int ctx_options,int out_state,int out_verify,int verify_mode,unsigned int verify_depth)781ebfedea0SLionel Sambuc static SSL_CTX *initialise_ssl_ctx(int server_mode, const char *engine_id,
782*0a6a1f1dSLionel Sambuc const char *CAfile, const char *cert,
783*0a6a1f1dSLionel Sambuc const char *key, const char *dcert,
784*0a6a1f1dSLionel Sambuc const char *dkey, const char *cipher_list,
785*0a6a1f1dSLionel Sambuc const char *dh_file,
786*0a6a1f1dSLionel Sambuc const char *dh_special, int tmp_rsa,
787*0a6a1f1dSLionel Sambuc int ctx_options, int out_state,
788*0a6a1f1dSLionel Sambuc int out_verify, int verify_mode,
789ebfedea0SLionel Sambuc unsigned int verify_depth)
790ebfedea0SLionel Sambuc {
791ebfedea0SLionel Sambuc SSL_CTX *ctx = NULL, *ret = NULL;
792ebfedea0SLionel Sambuc const SSL_METHOD *meth;
793ebfedea0SLionel Sambuc ENGINE *e = NULL;
794ebfedea0SLionel Sambuc
795ebfedea0SLionel Sambuc OpenSSL_add_ssl_algorithms();
796ebfedea0SLionel Sambuc SSL_load_error_strings();
797ebfedea0SLionel Sambuc
798ebfedea0SLionel Sambuc meth = (server_mode ? SSLv23_server_method() : SSLv23_client_method());
799ebfedea0SLionel Sambuc if (meth == NULL)
800ebfedea0SLionel Sambuc goto err;
801ebfedea0SLionel Sambuc if (engine_id) {
802ebfedea0SLionel Sambuc ENGINE_load_builtin_engines();
803ebfedea0SLionel Sambuc if ((e = ENGINE_by_id(engine_id)) == NULL) {
804ebfedea0SLionel Sambuc fprintf(stderr, "Error obtaining '%s' engine, openssl "
805ebfedea0SLionel Sambuc "errors follow\n", engine_id);
806ebfedea0SLionel Sambuc goto err;
807ebfedea0SLionel Sambuc }
808ebfedea0SLionel Sambuc if (!ENGINE_set_default(e, ENGINE_METHOD_ALL)) {
809ebfedea0SLionel Sambuc fprintf(stderr, "Error assigning '%s' engine, openssl "
810ebfedea0SLionel Sambuc "errors follow\n", engine_id);
811ebfedea0SLionel Sambuc goto err;
812ebfedea0SLionel Sambuc }
813ebfedea0SLionel Sambuc ENGINE_free(e);
814ebfedea0SLionel Sambuc }
815ebfedea0SLionel Sambuc if ((ctx = SSL_CTX_new(meth)) == NULL)
816ebfedea0SLionel Sambuc goto err;
817ebfedea0SLionel Sambuc /* cacert */
818ebfedea0SLionel Sambuc if (CAfile) {
819ebfedea0SLionel Sambuc if (!X509_STORE_load_locations(SSL_CTX_get_cert_store(ctx),
820ebfedea0SLionel Sambuc CAfile, NULL)) {
821*0a6a1f1dSLionel Sambuc fprintf(stderr, "Error loading CA cert(s) in '%s'\n", CAfile);
822ebfedea0SLionel Sambuc goto err;
823ebfedea0SLionel Sambuc }
824*0a6a1f1dSLionel Sambuc fprintf(stderr, "Info, operating with CA cert(s) in '%s'\n", CAfile);
825ebfedea0SLionel Sambuc } else
826ebfedea0SLionel Sambuc fprintf(stderr, "Info, operating without a CA cert(-list)\n");
827ebfedea0SLionel Sambuc if (!SSL_CTX_set_default_verify_paths(ctx)) {
828ebfedea0SLionel Sambuc fprintf(stderr, "Error setting default verify paths\n");
829ebfedea0SLionel Sambuc goto err;
830ebfedea0SLionel Sambuc }
831ebfedea0SLionel Sambuc
832ebfedea0SLionel Sambuc /* cert and key */
833ebfedea0SLionel Sambuc if ((cert || key) && !ctx_set_cert(ctx, cert, key))
834ebfedea0SLionel Sambuc goto err;
835ebfedea0SLionel Sambuc /* dcert and dkey */
836ebfedea0SLionel Sambuc if ((dcert || dkey) && !ctx_set_cert(ctx, dcert, dkey))
837ebfedea0SLionel Sambuc goto err;
838ebfedea0SLionel Sambuc /* temporary RSA key generation */
839ebfedea0SLionel Sambuc if (tmp_rsa)
840ebfedea0SLionel Sambuc SSL_CTX_set_tmp_rsa_callback(ctx, cb_generate_tmp_rsa);
841ebfedea0SLionel Sambuc
842ebfedea0SLionel Sambuc /* cipher_list */
843ebfedea0SLionel Sambuc if (cipher_list) {
844ebfedea0SLionel Sambuc if (!SSL_CTX_set_cipher_list(ctx, cipher_list)) {
845*0a6a1f1dSLionel Sambuc fprintf(stderr, "Error setting cipher list '%s'\n", cipher_list);
846ebfedea0SLionel Sambuc goto err;
847ebfedea0SLionel Sambuc }
848ebfedea0SLionel Sambuc fprintf(stderr, "Info, set cipher list '%s'\n", cipher_list);
849ebfedea0SLionel Sambuc } else
850ebfedea0SLionel Sambuc fprintf(stderr, "Info, operating with default cipher list\n");
851ebfedea0SLionel Sambuc
852ebfedea0SLionel Sambuc /* dh_file & dh_special */
853ebfedea0SLionel Sambuc if ((dh_file || dh_special) && !ctx_set_dh(ctx, dh_file, dh_special))
854ebfedea0SLionel Sambuc goto err;
855ebfedea0SLionel Sambuc
856ebfedea0SLionel Sambuc /* ctx_options */
857ebfedea0SLionel Sambuc SSL_CTX_set_options(ctx, ctx_options);
858ebfedea0SLionel Sambuc
859ebfedea0SLionel Sambuc /* out_state (output of SSL handshake states to screen). */
860ebfedea0SLionel Sambuc if (out_state)
861ebfedea0SLionel Sambuc cb_ssl_info_set_output(stderr);
862ebfedea0SLionel Sambuc
863ebfedea0SLionel Sambuc /* out_verify */
864ebfedea0SLionel Sambuc if (out_verify > 0) {
865ebfedea0SLionel Sambuc cb_ssl_verify_set_output(stderr);
866ebfedea0SLionel Sambuc cb_ssl_verify_set_level(out_verify);
867ebfedea0SLionel Sambuc }
868ebfedea0SLionel Sambuc
869ebfedea0SLionel Sambuc /* verify_depth */
870ebfedea0SLionel Sambuc cb_ssl_verify_set_depth(verify_depth);
871ebfedea0SLionel Sambuc
872ebfedea0SLionel Sambuc /* Success! (includes setting verify_mode) */
873ebfedea0SLionel Sambuc SSL_CTX_set_info_callback(ctx, cb_ssl_info);
874ebfedea0SLionel Sambuc SSL_CTX_set_verify(ctx, verify_mode, cb_ssl_verify);
875ebfedea0SLionel Sambuc ret = ctx;
876ebfedea0SLionel Sambuc err:
877ebfedea0SLionel Sambuc if (!ret) {
878ebfedea0SLionel Sambuc ERR_print_errors_fp(stderr);
879ebfedea0SLionel Sambuc if (ctx)
880ebfedea0SLionel Sambuc SSL_CTX_free(ctx);
881ebfedea0SLionel Sambuc }
882ebfedea0SLionel Sambuc return ret;
883ebfedea0SLionel Sambuc }
884ebfedea0SLionel Sambuc
885ebfedea0SLionel Sambuc /*****************/
886ebfedea0SLionel Sambuc /* Selector bits */
887ebfedea0SLionel Sambuc /*****************/
888ebfedea0SLionel Sambuc
selector_sets_init(select_sets_t * s)889ebfedea0SLionel Sambuc static void selector_sets_init(select_sets_t * s)
890ebfedea0SLionel Sambuc {
891ebfedea0SLionel Sambuc s->max = 0;
892ebfedea0SLionel Sambuc FD_ZERO(&s->reads);
893ebfedea0SLionel Sambuc FD_ZERO(&s->sends);
894ebfedea0SLionel Sambuc FD_ZERO(&s->excepts);
895ebfedea0SLionel Sambuc }
896*0a6a1f1dSLionel Sambuc
selector_init(tunala_selector_t * selector)897ebfedea0SLionel Sambuc static void selector_init(tunala_selector_t * selector)
898ebfedea0SLionel Sambuc {
899ebfedea0SLionel Sambuc selector_sets_init(&selector->last_selected);
900ebfedea0SLionel Sambuc selector_sets_init(&selector->next_select);
901ebfedea0SLionel Sambuc }
902ebfedea0SLionel Sambuc
903ebfedea0SLionel Sambuc #define SEL_EXCEPTS 0x00
904ebfedea0SLionel Sambuc #define SEL_READS 0x01
905ebfedea0SLionel Sambuc #define SEL_SENDS 0x02
selector_add_raw_fd(tunala_selector_t * s,int fd,int flags)906ebfedea0SLionel Sambuc static void selector_add_raw_fd(tunala_selector_t * s, int fd, int flags)
907ebfedea0SLionel Sambuc {
908ebfedea0SLionel Sambuc FD_SET(fd, &s->next_select.excepts);
909ebfedea0SLionel Sambuc if (flags & SEL_READS)
910ebfedea0SLionel Sambuc FD_SET(fd, &s->next_select.reads);
911ebfedea0SLionel Sambuc if (flags & SEL_SENDS)
912ebfedea0SLionel Sambuc FD_SET(fd, &s->next_select.sends);
913ebfedea0SLionel Sambuc /* Adjust "max" */
914ebfedea0SLionel Sambuc if (s->next_select.max < (fd + 1))
915ebfedea0SLionel Sambuc s->next_select.max = fd + 1;
916ebfedea0SLionel Sambuc }
917ebfedea0SLionel Sambuc
selector_add_listener(tunala_selector_t * selector,int fd)918ebfedea0SLionel Sambuc static void selector_add_listener(tunala_selector_t * selector, int fd)
919ebfedea0SLionel Sambuc {
920ebfedea0SLionel Sambuc selector_add_raw_fd(selector, fd, SEL_READS);
921ebfedea0SLionel Sambuc }
922ebfedea0SLionel Sambuc
selector_add_tunala(tunala_selector_t * s,tunala_item_t * t)923ebfedea0SLionel Sambuc static void selector_add_tunala(tunala_selector_t * s, tunala_item_t * t)
924ebfedea0SLionel Sambuc {
925ebfedea0SLionel Sambuc /* Set clean read if sm.clean_in is not full */
926ebfedea0SLionel Sambuc if (t->clean_read != -1) {
927ebfedea0SLionel Sambuc selector_add_raw_fd(s, t->clean_read,
928ebfedea0SLionel Sambuc (buffer_full(state_machine_get_buffer(&t->sm,
929*0a6a1f1dSLionel Sambuc SM_CLEAN_IN))
930*0a6a1f1dSLionel Sambuc ? SEL_EXCEPTS : SEL_READS));
931ebfedea0SLionel Sambuc }
932ebfedea0SLionel Sambuc /* Set clean send if sm.clean_out is not empty */
933ebfedea0SLionel Sambuc if (t->clean_send != -1) {
934ebfedea0SLionel Sambuc selector_add_raw_fd(s, t->clean_send,
935ebfedea0SLionel Sambuc (buffer_empty(state_machine_get_buffer(&t->sm,
936*0a6a1f1dSLionel Sambuc SM_CLEAN_OUT))
937*0a6a1f1dSLionel Sambuc ? SEL_EXCEPTS : SEL_SENDS));
938ebfedea0SLionel Sambuc }
939ebfedea0SLionel Sambuc /* Set dirty read if sm.dirty_in is not full */
940ebfedea0SLionel Sambuc if (t->dirty_read != -1) {
941ebfedea0SLionel Sambuc selector_add_raw_fd(s, t->dirty_read,
942ebfedea0SLionel Sambuc (buffer_full(state_machine_get_buffer(&t->sm,
943*0a6a1f1dSLionel Sambuc SM_DIRTY_IN))
944*0a6a1f1dSLionel Sambuc ? SEL_EXCEPTS : SEL_READS));
945ebfedea0SLionel Sambuc }
946ebfedea0SLionel Sambuc /* Set dirty send if sm.dirty_out is not empty */
947ebfedea0SLionel Sambuc if (t->dirty_send != -1) {
948ebfedea0SLionel Sambuc selector_add_raw_fd(s, t->dirty_send,
949ebfedea0SLionel Sambuc (buffer_empty(state_machine_get_buffer(&t->sm,
950*0a6a1f1dSLionel Sambuc SM_DIRTY_OUT))
951*0a6a1f1dSLionel Sambuc ? SEL_EXCEPTS : SEL_SENDS));
952ebfedea0SLionel Sambuc }
953ebfedea0SLionel Sambuc }
954ebfedea0SLionel Sambuc
selector_select(tunala_selector_t * selector)955ebfedea0SLionel Sambuc static int selector_select(tunala_selector_t * selector)
956ebfedea0SLionel Sambuc {
957ebfedea0SLionel Sambuc memcpy(&selector->last_selected, &selector->next_select,
958ebfedea0SLionel Sambuc sizeof(select_sets_t));
959ebfedea0SLionel Sambuc selector_sets_init(&selector->next_select);
960ebfedea0SLionel Sambuc return select(selector->last_selected.max,
961ebfedea0SLionel Sambuc &selector->last_selected.reads,
962ebfedea0SLionel Sambuc &selector->last_selected.sends,
963ebfedea0SLionel Sambuc &selector->last_selected.excepts, NULL);
964ebfedea0SLionel Sambuc }
965ebfedea0SLionel Sambuc
966*0a6a1f1dSLionel Sambuc /*
967*0a6a1f1dSLionel Sambuc * This returns -1 for error, 0 for no new connections, or 1 for success, in
968*0a6a1f1dSLionel Sambuc * which case *newfd is populated.
969*0a6a1f1dSLionel Sambuc */
selector_get_listener(tunala_selector_t * selector,int fd,int * newfd)970*0a6a1f1dSLionel Sambuc static int selector_get_listener(tunala_selector_t * selector, int fd,
971*0a6a1f1dSLionel Sambuc int *newfd)
972ebfedea0SLionel Sambuc {
973ebfedea0SLionel Sambuc if (FD_ISSET(fd, &selector->last_selected.excepts))
974ebfedea0SLionel Sambuc return -1;
975ebfedea0SLionel Sambuc if (!FD_ISSET(fd, &selector->last_selected.reads))
976ebfedea0SLionel Sambuc return 0;
977ebfedea0SLionel Sambuc if ((*newfd = ip_accept_connection(fd)) == -1)
978ebfedea0SLionel Sambuc return -1;
979ebfedea0SLionel Sambuc return 1;
980ebfedea0SLionel Sambuc }
981ebfedea0SLionel Sambuc
982ebfedea0SLionel Sambuc /************************/
983ebfedea0SLionel Sambuc /* "Tunala" world stuff */
984ebfedea0SLionel Sambuc /************************/
985ebfedea0SLionel Sambuc
tunala_world_make_room(tunala_world_t * world)986ebfedea0SLionel Sambuc static int tunala_world_make_room(tunala_world_t * world)
987ebfedea0SLionel Sambuc {
988ebfedea0SLionel Sambuc unsigned int newsize;
989ebfedea0SLionel Sambuc tunala_item_t *newarray;
990ebfedea0SLionel Sambuc
991ebfedea0SLionel Sambuc if (world->tunnels_used < world->tunnels_size)
992ebfedea0SLionel Sambuc return 1;
993ebfedea0SLionel Sambuc newsize = (world->tunnels_size == 0 ? 16 :
994ebfedea0SLionel Sambuc ((world->tunnels_size * 3) / 2));
995ebfedea0SLionel Sambuc if ((newarray = malloc(newsize * sizeof(tunala_item_t))) == NULL)
996ebfedea0SLionel Sambuc return 0;
997ebfedea0SLionel Sambuc memset(newarray, 0, newsize * sizeof(tunala_item_t));
998ebfedea0SLionel Sambuc if (world->tunnels_used > 0)
999ebfedea0SLionel Sambuc memcpy(newarray, world->tunnels,
1000ebfedea0SLionel Sambuc world->tunnels_used * sizeof(tunala_item_t));
1001ebfedea0SLionel Sambuc if (world->tunnels_size > 0)
1002ebfedea0SLionel Sambuc free(world->tunnels);
1003ebfedea0SLionel Sambuc /* migrate */
1004ebfedea0SLionel Sambuc world->tunnels = newarray;
1005ebfedea0SLionel Sambuc world->tunnels_size = newsize;
1006ebfedea0SLionel Sambuc return 1;
1007ebfedea0SLionel Sambuc }
1008ebfedea0SLionel Sambuc
tunala_world_new_item(tunala_world_t * world,int fd,const char * ip,unsigned short port,int flipped)1009ebfedea0SLionel Sambuc static int tunala_world_new_item(tunala_world_t * world, int fd,
1010*0a6a1f1dSLionel Sambuc const char *ip, unsigned short port,
1011*0a6a1f1dSLionel Sambuc int flipped)
1012ebfedea0SLionel Sambuc {
1013ebfedea0SLionel Sambuc tunala_item_t *item;
1014ebfedea0SLionel Sambuc int newfd;
1015ebfedea0SLionel Sambuc SSL *new_ssl = NULL;
1016ebfedea0SLionel Sambuc
1017ebfedea0SLionel Sambuc if (!tunala_world_make_room(world))
1018ebfedea0SLionel Sambuc return 0;
1019ebfedea0SLionel Sambuc if ((new_ssl = SSL_new(world->ssl_ctx)) == NULL) {
1020ebfedea0SLionel Sambuc fprintf(stderr, "Error creating new SSL\n");
1021ebfedea0SLionel Sambuc ERR_print_errors_fp(stderr);
1022ebfedea0SLionel Sambuc return 0;
1023ebfedea0SLionel Sambuc }
1024ebfedea0SLionel Sambuc item = world->tunnels + (world->tunnels_used++);
1025ebfedea0SLionel Sambuc state_machine_init(&item->sm);
1026ebfedea0SLionel Sambuc item->clean_read = item->clean_send =
1027ebfedea0SLionel Sambuc item->dirty_read = item->dirty_send = -1;
1028ebfedea0SLionel Sambuc if ((newfd = ip_create_connection_split(ip, port)) == -1)
1029ebfedea0SLionel Sambuc goto err;
1030*0a6a1f1dSLionel Sambuc /*
1031*0a6a1f1dSLionel Sambuc * Which way round? If we're a server, "fd" is the dirty side and the
1032ebfedea0SLionel Sambuc * connection we open is the clean one. For a client, it's the other way
1033ebfedea0SLionel Sambuc * around. Unless, of course, we're "flipped" in which case everything
1034*0a6a1f1dSLionel Sambuc * gets reversed. :-)
1035*0a6a1f1dSLionel Sambuc */
1036*0a6a1f1dSLionel Sambuc if ((world->server_mode && !flipped) || (!world->server_mode && flipped)) {
1037ebfedea0SLionel Sambuc item->dirty_read = item->dirty_send = fd;
1038ebfedea0SLionel Sambuc item->clean_read = item->clean_send = newfd;
1039ebfedea0SLionel Sambuc } else {
1040ebfedea0SLionel Sambuc item->clean_read = item->clean_send = fd;
1041ebfedea0SLionel Sambuc item->dirty_read = item->dirty_send = newfd;
1042ebfedea0SLionel Sambuc }
1043*0a6a1f1dSLionel Sambuc /*
1044*0a6a1f1dSLionel Sambuc * We use the SSL's "app_data" to indicate a call-back induced "kill"
1045*0a6a1f1dSLionel Sambuc */
1046ebfedea0SLionel Sambuc SSL_set_app_data(new_ssl, NULL);
1047ebfedea0SLionel Sambuc if (!state_machine_set_SSL(&item->sm, new_ssl, world->server_mode))
1048ebfedea0SLionel Sambuc goto err;
1049ebfedea0SLionel Sambuc return 1;
1050ebfedea0SLionel Sambuc err:
1051ebfedea0SLionel Sambuc tunala_world_del_item(world, world->tunnels_used - 1);
1052ebfedea0SLionel Sambuc return 0;
1053ebfedea0SLionel Sambuc
1054ebfedea0SLionel Sambuc }
1055ebfedea0SLionel Sambuc
tunala_world_del_item(tunala_world_t * world,unsigned int idx)1056ebfedea0SLionel Sambuc static void tunala_world_del_item(tunala_world_t * world, unsigned int idx)
1057ebfedea0SLionel Sambuc {
1058ebfedea0SLionel Sambuc tunala_item_t *item = world->tunnels + idx;
1059ebfedea0SLionel Sambuc if (item->clean_read != -1)
1060ebfedea0SLionel Sambuc close(item->clean_read);
1061ebfedea0SLionel Sambuc if (item->clean_send != item->clean_read)
1062ebfedea0SLionel Sambuc close(item->clean_send);
1063ebfedea0SLionel Sambuc item->clean_read = item->clean_send = -1;
1064ebfedea0SLionel Sambuc if (item->dirty_read != -1)
1065ebfedea0SLionel Sambuc close(item->dirty_read);
1066ebfedea0SLionel Sambuc if (item->dirty_send != item->dirty_read)
1067ebfedea0SLionel Sambuc close(item->dirty_send);
1068ebfedea0SLionel Sambuc item->dirty_read = item->dirty_send = -1;
1069ebfedea0SLionel Sambuc state_machine_close(&item->sm);
1070ebfedea0SLionel Sambuc /* OK, now we fix the item array */
1071ebfedea0SLionel Sambuc if (idx + 1 < world->tunnels_used)
1072ebfedea0SLionel Sambuc /* We need to scroll entries to the left */
1073ebfedea0SLionel Sambuc memmove(world->tunnels + idx,
1074ebfedea0SLionel Sambuc world->tunnels + (idx + 1),
1075*0a6a1f1dSLionel Sambuc (world->tunnels_used - (idx + 1)) * sizeof(tunala_item_t));
1076ebfedea0SLionel Sambuc world->tunnels_used--;
1077ebfedea0SLionel Sambuc }
1078ebfedea0SLionel Sambuc
tunala_item_io(tunala_selector_t * selector,tunala_item_t * item)1079ebfedea0SLionel Sambuc static int tunala_item_io(tunala_selector_t * selector, tunala_item_t * item)
1080ebfedea0SLionel Sambuc {
1081ebfedea0SLionel Sambuc int c_r, c_s, d_r, d_s; /* Four boolean flags */
1082ebfedea0SLionel Sambuc
1083ebfedea0SLionel Sambuc /* Take ourselves out of the gene-pool if there was an except */
1084ebfedea0SLionel Sambuc if ((item->clean_read != -1) && FD_ISSET(item->clean_read,
1085*0a6a1f1dSLionel Sambuc &selector->
1086*0a6a1f1dSLionel Sambuc last_selected.excepts))
1087ebfedea0SLionel Sambuc return 0;
1088ebfedea0SLionel Sambuc if ((item->clean_send != -1) && FD_ISSET(item->clean_send,
1089*0a6a1f1dSLionel Sambuc &selector->
1090*0a6a1f1dSLionel Sambuc last_selected.excepts))
1091ebfedea0SLionel Sambuc return 0;
1092ebfedea0SLionel Sambuc if ((item->dirty_read != -1) && FD_ISSET(item->dirty_read,
1093*0a6a1f1dSLionel Sambuc &selector->
1094*0a6a1f1dSLionel Sambuc last_selected.excepts))
1095ebfedea0SLionel Sambuc return 0;
1096ebfedea0SLionel Sambuc if ((item->dirty_send != -1) && FD_ISSET(item->dirty_send,
1097*0a6a1f1dSLionel Sambuc &selector->
1098*0a6a1f1dSLionel Sambuc last_selected.excepts))
1099ebfedea0SLionel Sambuc return 0;
1100ebfedea0SLionel Sambuc /* Grab our 4 IO flags */
1101ebfedea0SLionel Sambuc c_r = c_s = d_r = d_s = 0;
1102ebfedea0SLionel Sambuc if (item->clean_read != -1)
1103ebfedea0SLionel Sambuc c_r = FD_ISSET(item->clean_read, &selector->last_selected.reads);
1104ebfedea0SLionel Sambuc if (item->clean_send != -1)
1105ebfedea0SLionel Sambuc c_s = FD_ISSET(item->clean_send, &selector->last_selected.sends);
1106ebfedea0SLionel Sambuc if (item->dirty_read != -1)
1107ebfedea0SLionel Sambuc d_r = FD_ISSET(item->dirty_read, &selector->last_selected.reads);
1108ebfedea0SLionel Sambuc if (item->dirty_send != -1)
1109ebfedea0SLionel Sambuc d_s = FD_ISSET(item->dirty_send, &selector->last_selected.sends);
1110ebfedea0SLionel Sambuc /* If no IO has happened for us, skip needless data looping */
1111ebfedea0SLionel Sambuc if (!c_r && !c_s && !d_r && !d_s)
1112ebfedea0SLionel Sambuc return 1;
1113ebfedea0SLionel Sambuc if (c_r)
1114ebfedea0SLionel Sambuc c_r = (buffer_from_fd(state_machine_get_buffer(&item->sm,
1115*0a6a1f1dSLionel Sambuc SM_CLEAN_IN),
1116*0a6a1f1dSLionel Sambuc item->clean_read) <= 0);
1117ebfedea0SLionel Sambuc if (c_s)
1118ebfedea0SLionel Sambuc c_s = (buffer_to_fd(state_machine_get_buffer(&item->sm,
1119*0a6a1f1dSLionel Sambuc SM_CLEAN_OUT),
1120*0a6a1f1dSLionel Sambuc item->clean_send) <= 0);
1121ebfedea0SLionel Sambuc if (d_r)
1122ebfedea0SLionel Sambuc d_r = (buffer_from_fd(state_machine_get_buffer(&item->sm,
1123*0a6a1f1dSLionel Sambuc SM_DIRTY_IN),
1124*0a6a1f1dSLionel Sambuc item->dirty_read) <= 0);
1125ebfedea0SLionel Sambuc if (d_s)
1126ebfedea0SLionel Sambuc d_s = (buffer_to_fd(state_machine_get_buffer(&item->sm,
1127*0a6a1f1dSLionel Sambuc SM_DIRTY_OUT),
1128*0a6a1f1dSLionel Sambuc item->dirty_send) <= 0);
1129ebfedea0SLionel Sambuc /* If any of the flags is non-zero, that means they need closing */
1130ebfedea0SLionel Sambuc if (c_r) {
1131ebfedea0SLionel Sambuc close(item->clean_read);
1132ebfedea0SLionel Sambuc if (item->clean_send == item->clean_read)
1133ebfedea0SLionel Sambuc item->clean_send = -1;
1134ebfedea0SLionel Sambuc item->clean_read = -1;
1135ebfedea0SLionel Sambuc }
1136ebfedea0SLionel Sambuc if (c_s && (item->clean_send != -1)) {
1137ebfedea0SLionel Sambuc close(item->clean_send);
1138ebfedea0SLionel Sambuc if (item->clean_send == item->clean_read)
1139ebfedea0SLionel Sambuc item->clean_read = -1;
1140ebfedea0SLionel Sambuc item->clean_send = -1;
1141ebfedea0SLionel Sambuc }
1142ebfedea0SLionel Sambuc if (d_r) {
1143ebfedea0SLionel Sambuc close(item->dirty_read);
1144ebfedea0SLionel Sambuc if (item->dirty_send == item->dirty_read)
1145ebfedea0SLionel Sambuc item->dirty_send = -1;
1146ebfedea0SLionel Sambuc item->dirty_read = -1;
1147ebfedea0SLionel Sambuc }
1148ebfedea0SLionel Sambuc if (d_s && (item->dirty_send != -1)) {
1149ebfedea0SLionel Sambuc close(item->dirty_send);
1150ebfedea0SLionel Sambuc if (item->dirty_send == item->dirty_read)
1151ebfedea0SLionel Sambuc item->dirty_read = -1;
1152ebfedea0SLionel Sambuc item->dirty_send = -1;
1153ebfedea0SLionel Sambuc }
1154*0a6a1f1dSLionel Sambuc /*
1155*0a6a1f1dSLionel Sambuc * This function name is attributed to the term donated by David Schwartz
1156*0a6a1f1dSLionel Sambuc * on openssl-dev, message-ID:
1157*0a6a1f1dSLionel Sambuc * <NCBBLIEPOCbmasEKBEAKEEDGLIAA.davids@webmaster.com>. :-)
1158*0a6a1f1dSLionel Sambuc */
1159ebfedea0SLionel Sambuc if (!state_machine_churn(&item->sm))
1160*0a6a1f1dSLionel Sambuc /*
1161*0a6a1f1dSLionel Sambuc * If the SSL closes, it will also zero-out the _in buffers and will
1162*0a6a1f1dSLionel Sambuc * in future process just outgoing data. As and when the outgoing
1163*0a6a1f1dSLionel Sambuc * data has gone, it will return zero here to tell us to bail out.
1164*0a6a1f1dSLionel Sambuc */
1165ebfedea0SLionel Sambuc return 0;
1166ebfedea0SLionel Sambuc /* Otherwise, we return zero if both sides are dead. */
1167ebfedea0SLionel Sambuc if (((item->clean_read == -1) || (item->clean_send == -1)) &&
1168ebfedea0SLionel Sambuc ((item->dirty_read == -1) || (item->dirty_send == -1)))
1169ebfedea0SLionel Sambuc return 0;
1170*0a6a1f1dSLionel Sambuc /*
1171*0a6a1f1dSLionel Sambuc * If only one side closed, notify the SSL of this so it can take
1172*0a6a1f1dSLionel Sambuc * appropriate action.
1173*0a6a1f1dSLionel Sambuc */
1174ebfedea0SLionel Sambuc if ((item->clean_read == -1) || (item->clean_send == -1)) {
1175ebfedea0SLionel Sambuc if (!state_machine_close_clean(&item->sm))
1176ebfedea0SLionel Sambuc return 0;
1177ebfedea0SLionel Sambuc }
1178ebfedea0SLionel Sambuc if ((item->dirty_read == -1) || (item->dirty_send == -1)) {
1179ebfedea0SLionel Sambuc if (!state_machine_close_dirty(&item->sm))
1180ebfedea0SLionel Sambuc return 0;
1181ebfedea0SLionel Sambuc }
1182ebfedea0SLionel Sambuc return 1;
1183ebfedea0SLionel Sambuc }
1184