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_generate_parameters(512, DH_GENERATOR_5, 701 NULL, NULL)) == NULL) { 702 fprintf(stderr, "error!\n"); 703 return 0; 704 } 705 fprintf(stderr, "complete\n"); 706 goto do_it; 707 } 708 /* So, we're loading dh_file */ 709 if((fp = fopen(dh_file, "r")) == NULL) { 710 fprintf(stderr, "Error, couldn't open '%s' for DH parameters\n", 711 dh_file); 712 return 0; 713 } 714 dh = PEM_read_DHparams(fp, NULL, NULL, NULL); 715 fclose(fp); 716 if(dh == NULL) { 717 fprintf(stderr, "Error, could not parse DH parameters from '%s'\n", 718 dh_file); 719 return 0; 720 } 721 fprintf(stderr, "Info, using DH parameters from file '%s'\n", dh_file); 722do_it: 723 SSL_CTX_set_tmp_dh(ctx, dh); 724 DH_free(dh); 725 return 1; 726} 727 728static SSL_CTX *initialise_ssl_ctx(int server_mode, const char *engine_id, 729 const char *CAfile, const char *cert, const char *key, 730 const char *dcert, const char *dkey, const char *cipher_list, 731 const char *dh_file, const char *dh_special, int tmp_rsa, 732 int ctx_options, int out_state, int out_verify, int verify_mode, 733 unsigned int verify_depth) 734{ 735 SSL_CTX *ctx = NULL, *ret = NULL; 736 SSL_METHOD *meth; 737 ENGINE *e = NULL; 738 739 OpenSSL_add_ssl_algorithms(); 740 SSL_load_error_strings(); 741 742 meth = (server_mode ? SSLv23_server_method() : SSLv23_client_method()); 743 if(meth == NULL) 744 goto err; 745 if(engine_id) { 746 ENGINE_load_builtin_engines(); 747 if((e = ENGINE_by_id(engine_id)) == NULL) { 748 fprintf(stderr, "Error obtaining '%s' engine, openssl " 749 "errors follow\n", engine_id); 750 goto err; 751 } 752 if(!ENGINE_set_default(e, ENGINE_METHOD_ALL)) { 753 fprintf(stderr, "Error assigning '%s' engine, openssl " 754 "errors follow\n", engine_id); 755 goto err; 756 } 757 ENGINE_free(e); 758 } 759 if((ctx = SSL_CTX_new(meth)) == NULL) 760 goto err; 761 /* cacert */ 762 if(CAfile) { 763 if(!X509_STORE_load_locations(SSL_CTX_get_cert_store(ctx), 764 CAfile, NULL)) { 765 fprintf(stderr, "Error loading CA cert(s) in '%s'\n", 766 CAfile); 767 goto err; 768 } 769 fprintf(stderr, "Info, operating with CA cert(s) in '%s'\n", 770 CAfile); 771 } else 772 fprintf(stderr, "Info, operating without a CA cert(-list)\n"); 773 if(!SSL_CTX_set_default_verify_paths(ctx)) { 774 fprintf(stderr, "Error setting default verify paths\n"); 775 goto err; 776 } 777 778 /* cert and key */ 779 if((cert || key) && !ctx_set_cert(ctx, cert, key)) 780 goto err; 781 /* dcert and dkey */ 782 if((dcert || dkey) && !ctx_set_cert(ctx, dcert, dkey)) 783 goto err; 784 /* temporary RSA key generation */ 785 if(tmp_rsa) 786 SSL_CTX_set_tmp_rsa_callback(ctx, cb_generate_tmp_rsa); 787 788 /* cipher_list */ 789 if(cipher_list) { 790 if(!SSL_CTX_set_cipher_list(ctx, cipher_list)) { 791 fprintf(stderr, "Error setting cipher list '%s'\n", 792 cipher_list); 793 goto err; 794 } 795 fprintf(stderr, "Info, set cipher list '%s'\n", cipher_list); 796 } else 797 fprintf(stderr, "Info, operating with default cipher list\n"); 798 799 /* dh_file & dh_special */ 800 if((dh_file || dh_special) && !ctx_set_dh(ctx, dh_file, dh_special)) 801 goto err; 802 803 /* ctx_options */ 804 SSL_CTX_set_options(ctx, ctx_options); 805 806 /* out_state (output of SSL handshake states to screen). */ 807 if(out_state) 808 cb_ssl_info_set_output(stderr); 809 810 /* out_verify */ 811 if(out_verify > 0) { 812 cb_ssl_verify_set_output(stderr); 813 cb_ssl_verify_set_level(out_verify); 814 } 815 816 /* verify_depth */ 817 cb_ssl_verify_set_depth(verify_depth); 818 819 /* Success! (includes setting verify_mode) */ 820 SSL_CTX_set_info_callback(ctx, cb_ssl_info); 821 SSL_CTX_set_verify(ctx, verify_mode, cb_ssl_verify); 822 ret = ctx; 823err: 824 if(!ret) { 825 ERR_print_errors_fp(stderr); 826 if(ctx) 827 SSL_CTX_free(ctx); 828 } 829 return ret; 830} 831 832/*****************/ 833/* Selector bits */ 834/*****************/ 835 836static void selector_sets_init(select_sets_t *s) 837{ 838 s->max = 0; 839 FD_ZERO(&s->reads); 840 FD_ZERO(&s->sends); 841 FD_ZERO(&s->excepts); 842} 843static void selector_init(tunala_selector_t *selector) 844{ 845 selector_sets_init(&selector->last_selected); 846 selector_sets_init(&selector->next_select); 847} 848 849#define SEL_EXCEPTS 0x00 850#define SEL_READS 0x01 851#define SEL_SENDS 0x02 852static void selector_add_raw_fd(tunala_selector_t *s, int fd, int flags) 853{ 854 FD_SET(fd, &s->next_select.excepts); 855 if(flags & SEL_READS) 856 FD_SET(fd, &s->next_select.reads); 857 if(flags & SEL_SENDS) 858 FD_SET(fd, &s->next_select.sends); 859 /* Adjust "max" */ 860 if(s->next_select.max < (fd + 1)) 861 s->next_select.max = fd + 1; 862} 863 864static void selector_add_listener(tunala_selector_t *selector, int fd) 865{ 866 selector_add_raw_fd(selector, fd, SEL_READS); 867} 868 869static void selector_add_tunala(tunala_selector_t *s, tunala_item_t *t) 870{ 871 /* Set clean read if sm.clean_in is not full */ 872 if(t->clean_read != -1) { 873 selector_add_raw_fd(s, t->clean_read, 874 (buffer_full(state_machine_get_buffer(&t->sm, 875 SM_CLEAN_IN)) ? SEL_EXCEPTS : SEL_READS)); 876 } 877 /* Set clean send if sm.clean_out is not empty */ 878 if(t->clean_send != -1) { 879 selector_add_raw_fd(s, t->clean_send, 880 (buffer_empty(state_machine_get_buffer(&t->sm, 881 SM_CLEAN_OUT)) ? SEL_EXCEPTS : SEL_SENDS)); 882 } 883 /* Set dirty read if sm.dirty_in is not full */ 884 if(t->dirty_read != -1) { 885 selector_add_raw_fd(s, t->dirty_read, 886 (buffer_full(state_machine_get_buffer(&t->sm, 887 SM_DIRTY_IN)) ? SEL_EXCEPTS : SEL_READS)); 888 } 889 /* Set dirty send if sm.dirty_out is not empty */ 890 if(t->dirty_send != -1) { 891 selector_add_raw_fd(s, t->dirty_send, 892 (buffer_empty(state_machine_get_buffer(&t->sm, 893 SM_DIRTY_OUT)) ? SEL_EXCEPTS : SEL_SENDS)); 894 } 895} 896 897static int selector_select(tunala_selector_t *selector) 898{ 899 memcpy(&selector->last_selected, &selector->next_select, 900 sizeof(select_sets_t)); 901 selector_sets_init(&selector->next_select); 902 return select(selector->last_selected.max, 903 &selector->last_selected.reads, 904 &selector->last_selected.sends, 905 &selector->last_selected.excepts, NULL); 906} 907 908/* This returns -1 for error, 0 for no new connections, or 1 for success, in 909 * which case *newfd is populated. */ 910static int selector_get_listener(tunala_selector_t *selector, int fd, int *newfd) 911{ 912 if(FD_ISSET(fd, &selector->last_selected.excepts)) 913 return -1; 914 if(!FD_ISSET(fd, &selector->last_selected.reads)) 915 return 0; 916 if((*newfd = ip_accept_connection(fd)) == -1) 917 return -1; 918 return 1; 919} 920 921/************************/ 922/* "Tunala" world stuff */ 923/************************/ 924 925static int tunala_world_make_room(tunala_world_t *world) 926{ 927 unsigned int newsize; 928 tunala_item_t *newarray; 929 930 if(world->tunnels_used < world->tunnels_size) 931 return 1; 932 newsize = (world->tunnels_size == 0 ? 16 : 933 ((world->tunnels_size * 3) / 2)); 934 if((newarray = malloc(newsize * sizeof(tunala_item_t))) == NULL) 935 return 0; 936 memset(newarray, 0, newsize * sizeof(tunala_item_t)); 937 if(world->tunnels_used > 0) 938 memcpy(newarray, world->tunnels, 939 world->tunnels_used * sizeof(tunala_item_t)); 940 if(world->tunnels_size > 0) 941 free(world->tunnels); 942 /* migrate */ 943 world->tunnels = newarray; 944 world->tunnels_size = newsize; 945 return 1; 946} 947 948static int tunala_world_new_item(tunala_world_t *world, int fd, 949 const char *ip, unsigned short port, int flipped) 950{ 951 tunala_item_t *item; 952 int newfd; 953 SSL *new_ssl = NULL; 954 955 if(!tunala_world_make_room(world)) 956 return 0; 957 if((new_ssl = SSL_new(world->ssl_ctx)) == NULL) { 958 fprintf(stderr, "Error creating new SSL\n"); 959 ERR_print_errors_fp(stderr); 960 return 0; 961 } 962 item = world->tunnels + (world->tunnels_used++); 963 state_machine_init(&item->sm); 964 item->clean_read = item->clean_send = 965 item->dirty_read = item->dirty_send = -1; 966 if((newfd = ip_create_connection_split(ip, port)) == -1) 967 goto err; 968 /* Which way round? If we're a server, "fd" is the dirty side and the 969 * connection we open is the clean one. For a client, it's the other way 970 * around. Unless, of course, we're "flipped" in which case everything 971 * gets reversed. :-) */ 972 if((world->server_mode && !flipped) || 973 (!world->server_mode && flipped)) { 974 item->dirty_read = item->dirty_send = fd; 975 item->clean_read = item->clean_send = newfd; 976 } else { 977 item->clean_read = item->clean_send = fd; 978 item->dirty_read = item->dirty_send = newfd; 979 } 980 /* We use the SSL's "app_data" to indicate a call-back induced "kill" */ 981 SSL_set_app_data(new_ssl, NULL); 982 if(!state_machine_set_SSL(&item->sm, new_ssl, world->server_mode)) 983 goto err; 984 return 1; 985err: 986 tunala_world_del_item(world, world->tunnels_used - 1); 987 return 0; 988 989} 990 991static void tunala_world_del_item(tunala_world_t *world, unsigned int idx) 992{ 993 tunala_item_t *item = world->tunnels + idx; 994 if(item->clean_read != -1) 995 close(item->clean_read); 996 if(item->clean_send != item->clean_read) 997 close(item->clean_send); 998 item->clean_read = item->clean_send = -1; 999 if(item->dirty_read != -1) 1000 close(item->dirty_read); 1001 if(item->dirty_send != item->dirty_read) 1002 close(item->dirty_send); 1003 item->dirty_read = item->dirty_send = -1; 1004 state_machine_close(&item->sm); 1005 /* OK, now we fix the item array */ 1006 if(idx + 1 < world->tunnels_used) 1007 /* We need to scroll entries to the left */ 1008 memmove(world->tunnels + idx, 1009 world->tunnels + (idx + 1), 1010 (world->tunnels_used - (idx + 1)) * 1011 sizeof(tunala_item_t)); 1012 world->tunnels_used--; 1013} 1014 1015static int tunala_item_io(tunala_selector_t *selector, tunala_item_t *item) 1016{ 1017 int c_r, c_s, d_r, d_s; /* Four boolean flags */ 1018 1019 /* Take ourselves out of the gene-pool if there was an except */ 1020 if((item->clean_read != -1) && FD_ISSET(item->clean_read, 1021 &selector->last_selected.excepts)) 1022 return 0; 1023 if((item->clean_send != -1) && FD_ISSET(item->clean_send, 1024 &selector->last_selected.excepts)) 1025 return 0; 1026 if((item->dirty_read != -1) && FD_ISSET(item->dirty_read, 1027 &selector->last_selected.excepts)) 1028 return 0; 1029 if((item->dirty_send != -1) && FD_ISSET(item->dirty_send, 1030 &selector->last_selected.excepts)) 1031 return 0; 1032 /* Grab our 4 IO flags */ 1033 c_r = c_s = d_r = d_s = 0; 1034 if(item->clean_read != -1) 1035 c_r = FD_ISSET(item->clean_read, &selector->last_selected.reads); 1036 if(item->clean_send != -1) 1037 c_s = FD_ISSET(item->clean_send, &selector->last_selected.sends); 1038 if(item->dirty_read != -1) 1039 d_r = FD_ISSET(item->dirty_read, &selector->last_selected.reads); 1040 if(item->dirty_send != -1) 1041 d_s = FD_ISSET(item->dirty_send, &selector->last_selected.sends); 1042 /* If no IO has happened for us, skip needless data looping */ 1043 if(!c_r && !c_s && !d_r && !d_s) 1044 return 1; 1045 if(c_r) 1046 c_r = (buffer_from_fd(state_machine_get_buffer(&item->sm, 1047 SM_CLEAN_IN), item->clean_read) <= 0); 1048 if(c_s) 1049 c_s = (buffer_to_fd(state_machine_get_buffer(&item->sm, 1050 SM_CLEAN_OUT), item->clean_send) <= 0); 1051 if(d_r) 1052 d_r = (buffer_from_fd(state_machine_get_buffer(&item->sm, 1053 SM_DIRTY_IN), item->dirty_read) <= 0); 1054 if(d_s) 1055 d_s = (buffer_to_fd(state_machine_get_buffer(&item->sm, 1056 SM_DIRTY_OUT), item->dirty_send) <= 0); 1057 /* If any of the flags is non-zero, that means they need closing */ 1058 if(c_r) { 1059 close(item->clean_read); 1060 if(item->clean_send == item->clean_read) 1061 item->clean_send = -1; 1062 item->clean_read = -1; 1063 } 1064 if(c_s && (item->clean_send != -1)) { 1065 close(item->clean_send); 1066 if(item->clean_send == item->clean_read) 1067 item->clean_read = -1; 1068 item->clean_send = -1; 1069 } 1070 if(d_r) { 1071 close(item->dirty_read); 1072 if(item->dirty_send == item->dirty_read) 1073 item->dirty_send = -1; 1074 item->dirty_read = -1; 1075 } 1076 if(d_s && (item->dirty_send != -1)) { 1077 close(item->dirty_send); 1078 if(item->dirty_send == item->dirty_read) 1079 item->dirty_read = -1; 1080 item->dirty_send = -1; 1081 } 1082 /* This function name is attributed to the term donated by David 1083 * Schwartz on openssl-dev, message-ID: 1084 * <NCBBLIEPOCNJOAEKBEAKEEDGLIAA.davids@webmaster.com>. :-) */ 1085 if(!state_machine_churn(&item->sm)) 1086 /* If the SSL closes, it will also zero-out the _in buffers 1087 * and will in future process just outgoing data. As and 1088 * when the outgoing data has gone, it will return zero 1089 * here to tell us to bail out. */ 1090 return 0; 1091 /* Otherwise, we return zero if both sides are dead. */ 1092 if(((item->clean_read == -1) || (item->clean_send == -1)) && 1093 ((item->dirty_read == -1) || (item->dirty_send == -1))) 1094 return 0; 1095 /* If only one side closed, notify the SSL of this so it can take 1096 * appropriate action. */ 1097 if((item->clean_read == -1) || (item->clean_send == -1)) { 1098 if(!state_machine_close_clean(&item->sm)) 1099 return 0; 1100 } 1101 if((item->dirty_read == -1) || (item->dirty_send == -1)) { 1102 if(!state_machine_close_dirty(&item->sm)) 1103 return 0; 1104 } 1105 return 1; 1106} 1107 1108