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