📄 tunala.c
字号:
if(argc < 2) return usage("-dcert requires an argument", 0); argc--; argv++; if(strcmp(*argv, "NULL") == 0) dcert = NULL; else dcert = *argv; goto next_arg; } else if(strcmp(*argv, "-dkey") == 0) { if(argc < 2) return usage("-dkey requires an argument", 0); argc--; argv++; if(strcmp(*argv, "NULL") == 0) dkey = NULL; else dkey = *argv; goto next_arg; } else if(strcmp(*argv, "-engine") == 0) { if(argc < 2) return usage("-engine requires an argument", 0); argc--; argv++; engine_id = *argv; goto next_arg; } else if(strcmp(*argv, "-server") == 0) { if(argc < 2) return usage("-server requires an argument", 0); argc--; argv++; if(!parse_server_mode(*argv, &server_mode)) return 1; goto next_arg; } else if(strcmp(*argv, "-flipped") == 0) { if(argc < 2) return usage("-flipped requires an argument", 0); argc--; argv++; if(!parse_server_mode(*argv, &flipped)) return 1; goto next_arg; } else if(strcmp(*argv, "-cipher") == 0) { if(argc < 2) return usage("-cipher requires an argument", 0); argc--; argv++; cipher_list = *argv; goto next_arg; } else if(strcmp(*argv, "-dh_file") == 0) { if(argc < 2) return usage("-dh_file requires an argument", 0); if(dh_special) return usage("cannot mix -dh_file with " "-dh_special", 0); argc--; argv++; dh_file = *argv; goto next_arg; } else if(strcmp(*argv, "-dh_special") == 0) { if(argc < 2) return usage("-dh_special requires an argument", 0); if(dh_file) return usage("cannot mix -dh_file with " "-dh_special", 0); argc--; argv++; if(!parse_dh_special(*argv, &dh_special)) return 1; goto next_arg; } else if(strcmp(*argv, "-no_tmp_rsa") == 0) { tmp_rsa = 0; goto next_arg; } else if(strcmp(*argv, "-no_ssl2") == 0) { ctx_options |= SSL_OP_NO_SSLv2; goto next_arg; } else if(strcmp(*argv, "-no_ssl3") == 0) { ctx_options |= SSL_OP_NO_SSLv3; goto next_arg; } else if(strcmp(*argv, "-no_tls1") == 0) { ctx_options |= SSL_OP_NO_TLSv1; goto next_arg; } else if(strcmp(*argv, "-v_peer") == 0) { verify_mode |= SSL_VERIFY_PEER; goto next_arg; } else if(strcmp(*argv, "-v_strict") == 0) { verify_mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT; goto next_arg; } else if(strcmp(*argv, "-v_once") == 0) { verify_mode |= SSL_VERIFY_CLIENT_ONCE; goto next_arg; } else if(strcmp(*argv, "-v_depth") == 0) { if(argc < 2) return usage("-v_depth requires an argument", 0); argc--; argv++; if(!parse_verify_depth(*argv, &verify_depth)) return 1; goto next_arg; } else if(strcmp(*argv, "-out_state") == 0) { out_state = 1; goto next_arg; } else if(strcmp(*argv, "-out_verify") == 0) { if(argc < 2) return usage("-out_verify requires an argument", 0); argc--; argv++; if(!parse_verify_level(*argv, &out_verify)) return 1; goto next_arg; } else if(strcmp(*argv, "-out_totals") == 0) { out_totals = 1; goto next_arg; } else if(strcmp(*argv, "-out_conns") == 0) { out_conns = 1; goto next_arg; } else if((strcmp(*argv, "-h") == 0) || (strcmp(*argv, "-help") == 0) || (strcmp(*argv, "-?") == 0)) { fprintf(stderr, "%s\n", helpstring); return 0; } else return usage(*argv, 1); } /* Run any sanity checks we want here */ if(!cert && !dcert && server_mode) fprintf(stderr, "WARNING: you are running an SSL server without " "a certificate - this may not work!\n"); /* Initialise network stuff */ if(!ip_initialise()) return err_str0("ip_initialise failed"); /* Create the SSL_CTX */ if((world.ssl_ctx = initialise_ssl_ctx(server_mode, engine_id, cacert, cert, key, dcert, dkey, cipher_list, dh_file, dh_special, tmp_rsa, ctx_options, out_state, out_verify, verify_mode, verify_depth)) == NULL) return err_str1("initialise_ssl_ctx(engine_id=%s) failed", (engine_id == NULL) ? "NULL" : engine_id); if(engine_id) fprintf(stderr, "Info, engine '%s' initialised\n", engine_id); /* Create the listener */ if((world.listen_fd = ip_create_listener(listenhost)) == -1) return err_str1("ip_create_listener(%s) failed", listenhost); fprintf(stderr, "Info, listening on '%s'\n", listenhost); if(!ip_parse_address(proxyhost, &proxy_ip, &proxy_port, 0)) return err_str1("ip_parse_address(%s) failed", proxyhost); fprintf(stderr, "Info, proxying to '%s' (%d.%d.%d.%d:%d)\n", proxyhost, (int)proxy_ip[0], (int)proxy_ip[1], (int)proxy_ip[2], (int)proxy_ip[3], (int)proxy_port); fprintf(stderr, "Info, set maxtunnels to %d\n", (int)max_tunnels); fprintf(stderr, "Info, set to operate as an SSL %s\n", (server_mode ? "server" : "client")); /* Initialise the rest of the stuff */ world.tunnels_used = world.tunnels_size = 0; world.tunnels = NULL; world.server_mode = server_mode; selector_init(&world.selector);/* We're ready to loop */main_loop: /* Should we listen for *new* tunnels? */ if(world.tunnels_used < max_tunnels) selector_add_listener(&world.selector, world.listen_fd); /* We should add in our existing tunnels */ for(loop = 0; loop < world.tunnels_used; loop++) selector_add_tunala(&world.selector, world.tunnels + loop); /* Now do the select */ switch(selector_select(&world.selector)) { case -1: if(errno != EINTR) { fprintf(stderr, "selector_select returned a " "badness error.\n"); goto shouldnt_happen; } fprintf(stderr, "Warn, selector interrupted by a signal\n"); goto main_loop; case 0: fprintf(stderr, "Warn, selector_select returned 0 - signal?""?\n"); goto main_loop; default: break; } /* Accept new connection if we should and can */ if((world.tunnels_used < max_tunnels) && (selector_get_listener( &world.selector, world.listen_fd, &newfd) == 1)) { /* We have a new connection */ if(!tunala_world_new_item(&world, newfd, proxy_ip, proxy_port, flipped)) fprintf(stderr, "tunala_world_new_item failed\n"); else if(out_conns) fprintf(stderr, "Info, new tunnel opened, now up to " "%d\n", world.tunnels_used); } /* Give each tunnel its moment, note the while loop is because it makes * the logic easier than with "for" to deal with an array that may shift * because of deletes. */ loop = 0; t_item = world.tunnels; while(loop < world.tunnels_used) { if(!tunala_item_io(&world.selector, t_item)) { /* We're closing whether for reasons of an error or a * natural close. Don't increment loop or t_item because * the next item is moving to us! */ if(!out_totals) goto skip_totals; fprintf(stderr, "Tunnel closing, traffic stats follow\n"); /* Display the encrypted (over the network) stats */ fprintf(stderr, io_stats_dirty, buffer_total_in(state_machine_get_buffer( &t_item->sm,SM_DIRTY_IN)), buffer_total_out(state_machine_get_buffer( &t_item->sm,SM_DIRTY_OUT))); /* Display the local (tunnelled) stats. NB: Data we * *receive* is data sent *out* of the state_machine on * its 'clean' side. Hence the apparent back-to-front * OUT/IN mixup here :-) */ fprintf(stderr, io_stats_clean, buffer_total_out(state_machine_get_buffer( &t_item->sm,SM_CLEAN_OUT)), buffer_total_in(state_machine_get_buffer( &t_item->sm,SM_CLEAN_IN)));skip_totals: tunala_world_del_item(&world, loop); if(out_conns) fprintf(stderr, "Info, tunnel closed, down to %d\n", world.tunnels_used); } else { /* Move to the next item */ loop++; t_item++; } } goto main_loop; /* Should never get here */shouldnt_happen: abort(); return 1;}/****************//* OpenSSL bits *//****************/static int ctx_set_cert(SSL_CTX *ctx, const char *cert, const char *key){ FILE *fp = NULL; X509 *x509 = NULL; EVP_PKEY *pkey = NULL; int toret = 0; /* Assume an error */ /* cert */ if(cert) { if((fp = fopen(cert, "r")) == NULL) { fprintf(stderr, "Error opening cert file '%s'\n", cert); goto err; } if(!PEM_read_X509(fp, &x509, NULL, NULL)) { fprintf(stderr, "Error reading PEM cert from '%s'\n", cert); goto err; } if(!SSL_CTX_use_certificate(ctx, x509)) { fprintf(stderr, "Error, cert in '%s' can not be used\n", cert); goto err; } /* Clear the FILE* for reuse in the "key" code */ fclose(fp); fp = NULL; fprintf(stderr, "Info, operating with cert in '%s'\n", cert); /* If a cert was given without matching key, we assume the same * file contains the required key. */ if(!key) key = cert; } else { if(key) fprintf(stderr, "Error, can't specify a key without a " "corresponding certificate\n"); else fprintf(stderr, "Error, ctx_set_cert called with " "NULLs!\n"); goto err; } /* key */ if(key) { if((fp = fopen(key, "r")) == NULL) { fprintf(stderr, "Error opening key file '%s'\n", key); goto err; } if(!PEM_read_PrivateKey(fp, &pkey, NULL, NULL)) { fprintf(stderr, "Error reading PEM key from '%s'\n", key); goto err; } if(!SSL_CTX_use_PrivateKey(ctx, pkey)) { fprintf(stderr, "Error, key in '%s' can not be used\n", key); goto err; } fprintf(stderr, "Info, operating with key in '%s'\n", key); } else fprintf(stderr, "Info, operating without a cert or key\n"); /* Success */ toret = 1; err: if(x509) X509_free(x509); if(pkey) EVP_PKEY_free(pkey); if(fp) fclose(fp); return toret;}static int ctx_set_dh(SSL_CTX *ctx, const char *dh_file, const char *dh_special){ DH *dh = NULL; FILE *fp = NULL; if(dh_special) { if(strcmp(dh_special, "NULL") == 0) return 1; if(strcmp(dh_special, "standard") == 0) { if((dh = get_dh512()) == NULL) { fprintf(stderr, "Error, can't parse 'standard'" " DH parameters\n"); return 0; } fprintf(stderr, "Info, using 'standard' DH parameters\n"); goto do_it; } if(strcmp(dh_special, "generate") != 0) /* This shouldn't happen - screening values is handled * in main(). */ abort(); fprintf(stderr, "Info, generating DH parameters ... "); fflush(stderr); if((dh = DH_generate_parameters(512, DH_GENERATOR_5, NULL, NULL)) == NULL) { fprintf(stderr, "error!\n"); return 0; } fprintf(stderr, "complete\n"); goto do_it; } /* So, we're loading dh_file */ if((fp = fopen(dh_file, "r")) == NULL) { fprintf(stderr, "Error, couldn't open '%s' for DH parameters\n", dh_file); return 0; } dh = PEM_read_DHparams(fp, NULL, NULL, NULL); fclose(fp); if(dh == NULL) { fprintf(stderr, "Error, could not parse DH parameters from '%s'\n", dh_file); return 0; } fprintf(stderr, "Info, using DH parameters from file '%s'\n", dh_file);do_it: SSL_CTX_set_tmp_dh(ctx, dh); DH_free(dh); return 1;}static SSL_CTX *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){ SSL_CTX *ctx = NULL, *ret = NULL; SSL_METHOD *meth; ENGINE *e = NULL; OpenSSL_add_ssl_algorithms(); SSL_load_error_strings();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -