X-Git-Url: http://www.privoxy.org/gitweb/?p=privoxy.git;a=blobdiff_plain;f=jcc.c;h=2a8c1669ed59c32a88baa2e782cb73dc43b3839d;hp=1cafb1c76c490b725e5bf5ee6b1fca696248bf5a;hb=75301323495579ff27bdaaea67e31e2df83475fc;hpb=1cca8d974c645ef98cf343cb4dbf1ce42d5e88bd diff --git a/jcc.c b/jcc.c index 1cafb1c7..2a8c1669 100644 --- a/jcc.c +++ b/jcc.c @@ -5,8 +5,8 @@ * Purpose : Main file. Contains main() method, main loop, and * the main connection-handling function. * - * Copyright : Written by and Copyright (C) 2001-2019 the - * Privoxy team. http://www.privoxy.org/ + * Copyright : Written by and Copyright (C) 2001-2020 the + * Privoxy team. https://www.privoxy.org/ * * Based on the Internet Junkbuster originally written * by and Copyright (C) 1997 Anonymous Coders and @@ -62,10 +62,8 @@ #else /* ifndef _WIN32 */ -# if !defined (__OS2__) # include # include -# endif /* ndef __OS2__ */ # include # include # include @@ -86,14 +84,6 @@ # include /* declarations for threads and stuff. */ # endif -# if defined(__EMX__) || defined(__OS2__) -# include /* OS/2/EMX needs a little help with select */ -# endif -# ifdef __OS2__ -#define INCL_DOS -# include -# endif - #ifdef HAVE_POLL #ifdef __GLIBC__ #include @@ -112,7 +102,7 @@ #include "project.h" #include "list.h" #include "jcc.h" -#ifdef FEATURE_HTTPS_FILTERING +#ifdef FEATURE_HTTPS_INSPECTION #include "ssl.h" #endif #include "filters.h" @@ -143,10 +133,10 @@ int urls_rejected = 0; /* total nr of urls rejected */ int g_terminate = 0; #endif -#if !defined(_WIN32) && !defined(__OS2__) +#if !defined(_WIN32) static void sig_handler(int the_signal); #endif -static int client_protocol_is_unsupported(const struct client_state *csp, char *req); +static int client_protocol_is_unsupported(struct client_state *csp, char *req); static jb_err get_request_destination_elsewhere(struct client_state *csp, struct list *headers); static jb_err get_server_headers(struct client_state *csp); static const char *crunch_reason(const struct http_response *rsp); @@ -156,6 +146,7 @@ static jb_err receive_client_request(struct client_state *csp); static jb_err parse_client_request(struct client_state *csp); static void build_request_line(struct client_state *csp, const struct forward_spec *fwd, char **request_line); static jb_err change_request_destination(struct client_state *csp); +static void handle_established_connection(struct client_state *csp); static void chat(struct client_state *csp); static void serve(struct client_state *csp); #if !defined(_WIN32) || defined(_WIN_CONSOLE) @@ -176,10 +167,6 @@ static int32 server_thread(void *data); #define sleep(N) Sleep(((N) * 1000)) #endif -#ifdef __OS2__ -#define sleep(N) DosSleep(((N) * 100)) -#endif - #ifdef FUZZ int process_fuzzed_input(char *fuzz_input_type, char *fuzz_input_file); void show_fuzz_usage(const char *name); @@ -193,12 +180,10 @@ privoxy_mutex_t log_mutex; privoxy_mutex_t log_init_mutex; privoxy_mutex_t connection_reuse_mutex; -#ifdef LIMIT_MUTEX_NUMBER -privoxy_mutex_t certificates_mutexes[32]; -#else -privoxy_mutex_t certificates_mutexes[65536]; -#endif /* LIMIT_MUTEX_NUMBER */ -privoxy_mutex_t rng_mutex; +#ifdef FEATURE_HTTPS_INSPECTION +privoxy_mutex_t certificate_mutex; +privoxy_mutex_t ssl_init_mutex; +#endif #ifdef FEATURE_EXTERNAL_FILTERS privoxy_mutex_t external_filter_mutex; @@ -206,6 +191,10 @@ privoxy_mutex_t external_filter_mutex; #ifdef FEATURE_CLIENT_TAGS privoxy_mutex_t client_tags_mutex; #endif +#ifdef FEATURE_EXTENDED_STATISTICS +privoxy_mutex_t filter_statistics_mutex; +privoxy_mutex_t block_statistics_mutex; +#endif #if !defined(HAVE_GETHOSTBYADDR_R) || !defined(HAVE_GETHOSTBYNAME_R) privoxy_mutex_t resolver_mutex; @@ -344,7 +333,7 @@ static const struct cruncher crunchers_light[] = { * * here? */ -#if !defined(_WIN32) && !defined(__OS2__) +#if !defined(_WIN32) /********************************************************************* * * Function : sig_handler @@ -447,7 +436,7 @@ static unsigned int get_write_delay(const struct client_state *csp) * FALSE if the request doesn't look invalid. * *********************************************************************/ -static int client_protocol_is_unsupported(const struct client_state *csp, char *req) +static int client_protocol_is_unsupported(struct client_state *csp, char *req) { /* * If it's a FTP or gopher request, we don't support it. @@ -483,8 +472,20 @@ static int client_protocol_is_unsupported(const struct client_state *csp, char * log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 400 0", csp->ip_addr_str, req); freez(req); - write_socket_delayed(csp->cfd, response, strlen(response), - get_write_delay(csp)); + +#ifdef FEATURE_HTTPS_INSPECTION + if (client_use_ssl(csp)) + { + ssl_send_data_delayed(&(csp->ssl_client_attr), + (const unsigned char *)response, strlen(response), + get_write_delay(csp)); + } + else +#endif + { + write_socket_delayed(csp->cfd, response, strlen(response), + get_write_delay(csp)); + } return TRUE; } @@ -558,8 +559,6 @@ static int client_has_unsupported_expectations(const struct client_state *csp) *********************************************************************/ static jb_err get_request_destination_elsewhere(struct client_state *csp, struct list *headers) { - char *req; - if (!(csp->config->feature_flags & RUNTIME_FEATURE_ACCEPT_INTERCEPTED_REQUESTS)) { log_error(LOG_LEVEL_ERROR, "%s's request: \'%s\' is invalid." @@ -577,10 +576,8 @@ static jb_err get_request_destination_elsewhere(struct client_state *csp, struct } else if (JB_ERR_OK == get_destination_from_headers(headers, csp->http)) { -#ifndef FEATURE_EXTENDED_HOST_PATTERNS /* Split the domain we just got for pattern matching */ init_domain_components(csp->http); -#endif return JB_ERR_OK; } @@ -588,15 +585,12 @@ static jb_err get_request_destination_elsewhere(struct client_state *csp, struct { /* We can't work without destination. Go spread the news.*/ - req = list_to_text(headers); - chomp(req); /* XXX: Use correct size */ log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 400 0", csp->ip_addr_str, csp->http->cmd); log_error(LOG_LEVEL_ERROR, - "Privoxy was unable to get the destination for %s's request:\n%s\n%s", - csp->ip_addr_str, csp->http->cmd, req); - freez(req); + "Privoxy was unable to get the destination for %s's request: %s", + csp->ip_addr_str, csp->http->cmd); write_socket_delayed(csp->cfd, MISSING_DESTINATION_RESPONSE, strlen(MISSING_DESTINATION_RESPONSE), get_write_delay(csp)); @@ -839,23 +833,37 @@ static void send_crunch_response(struct client_state *csp, struct http_response /* Log that the request was crunched and why. */ log_applied_actions(csp->action); - log_error(LOG_LEVEL_CRUNCH, "%s: %s", crunch_reason(rsp), http->url); - log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" %s %u", - csp->ip_addr_str, http->ocmd, status_code, rsp->content_length); - +#ifdef FEATURE_HTTPS_INSPECTION + if (client_use_ssl(csp)) + { + log_error(LOG_LEVEL_CRUNCH, "%s: https://%s%s", crunch_reason(rsp), + http->hostport, http->path); + log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s https://%s%s %s\" %s %lu", + csp->ip_addr_str, http->gpc, http->hostport, http->path, + http->version, status_code, rsp->content_length); + } + else +#endif + { + log_error(LOG_LEVEL_CRUNCH, "%s: %s", crunch_reason(rsp), http->url); + log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" %s %lu", + csp->ip_addr_str, http->ocmd, status_code, rsp->content_length); + } /* Write the answer to the client */ -#ifdef FEATURE_HTTPS_FILTERING +#ifdef FEATURE_HTTPS_INSPECTION if (client_use_ssl(csp)) { - if ((ssl_send_data(&(csp->mbedtls_client_attr.ssl), - (const unsigned char *)rsp->head, rsp->head_length) < 0) - || (ssl_send_data(&(csp->mbedtls_client_attr.ssl), - (const unsigned char *)rsp->body, rsp->content_length) < 0)) + if ((ssl_send_data_delayed(&(csp->ssl_client_attr), + (const unsigned char *)rsp->head, rsp->head_length, + get_write_delay(csp)) < 0) + || (ssl_send_data_delayed(&(csp->ssl_client_attr), + (const unsigned char *)rsp->body, rsp->content_length, + get_write_delay(csp)) < 0)) { /* There is nothing we can do about it. */ log_error(LOG_LEVEL_CONNECT, "Couldn't deliver the error message " - "for %s through client socket %d using TLS/SSL", - http->url, csp->cfd); + "for https://%s%s through client socket %d using TLS/SSL", + http->hostport, http->url, csp->cfd); } } else @@ -976,10 +984,10 @@ static void build_request_line(struct client_state *csp, const struct forward_sp * if +downgrade action applies. */ if ((csp->action->flags & ACTION_DOWNGRADE) - && (!strcmpic(http->ver, "HTTP/1.1"))) + && (!strcmpic(http->version, "HTTP/1.1"))) { - freez(http->ver); - http->ver = strdup_or_die("HTTP/1.0"); + freez(http->version); + http->version = strdup_or_die("HTTP/1.0"); } /* @@ -998,7 +1006,7 @@ static void build_request_line(struct client_state *csp, const struct forward_sp string_append(request_line, http->path); } string_append(request_line, " "); - string_append(request_line, http->ver); + string_append(request_line, http->version); if (*request_line == NULL) { @@ -1163,6 +1171,22 @@ void save_connection_destination(jb_socket sfd, server_connection->gateway_host = NULL; } server_connection->gateway_port = fwd->gateway_port; + if (NULL != fwd->auth_username) + { + server_connection->auth_username = strdup_or_die(fwd->auth_username); + } + else + { + server_connection->auth_username = NULL; + } + if (NULL != fwd->auth_password) + { + server_connection->auth_password = strdup_or_die(fwd->auth_password); + } + else + { + server_connection->auth_password = NULL; + } if (NULL != fwd->forward_host) { @@ -1174,6 +1198,7 @@ void save_connection_destination(jb_socket sfd, } server_connection->forward_port = fwd->forward_port; } +#endif /* FEATURE_CONNECTION_KEEP_ALIVE */ /********************************************************************* @@ -1274,7 +1299,6 @@ static void verify_request_length(struct client_state *csp) log_error(LOG_LEVEL_CONNECT, "Complete client request received."); } } -#endif /* FEATURE_CONNECTION_KEEP_ALIVE */ /********************************************************************* @@ -1535,7 +1559,7 @@ static jb_err receive_chunked_client_request_body(struct client_state *csp) return JB_ERR_PARSE; } log_error(LOG_LEVEL_CONNECT, - "Chunked client body completely read. Length: %d", body_length); + "Chunked client body completely read. Length: %lu", body_length); csp->expected_client_content_length = body_length; return JB_ERR_OK; @@ -1598,7 +1622,7 @@ extern int fuzz_client_request(struct client_state *csp, char *fuzz_input_file) if (strcmp(fuzz_input_file, "-") != 0) { log_error(LOG_LEVEL_FATAL, - "Fuzzed client requests can currenty only be read from stdin (-)."); + "Fuzzed client requests can currently only be read from stdin (-)."); } err = receive_client_request(csp); if (err != JB_ERR_OK) @@ -1889,12 +1913,13 @@ static jb_err parse_client_request(struct client_state *csp) #ifdef FEATURE_CONNECTION_KEEP_ALIVE if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE) - && (!strcmpic(csp->http->ver, "HTTP/1.1")) + && (!strcmpic(csp->http->version, "HTTP/1.1")) && (csp->http->ssl == 0)) { /* Assume persistence until further notice */ csp->flags |= CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE; } +#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ if (csp->http->ssl == 0) { @@ -1915,11 +1940,12 @@ static jb_err parse_client_request(struct client_state *csp) } verify_request_length(csp); } +#ifndef FEATURE_HTTPS_INSPECTION else { csp->flags |= CSP_FLAG_SERVER_SOCKET_TAINTED; } -#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ +#endif err = sed(csp, FILTER_CLIENT_HEADERS); if (JB_ERR_OK != err) @@ -2014,7 +2040,77 @@ static int send_http_request(struct client_state *csp) } -#ifdef FEATURE_HTTPS_FILTERING +#ifdef FEATURE_HTTPS_INSPECTION +/********************************************************************* + * + * Function : receive_and_send_encrypted_post_data + * + * Description : Reads remaining POST data from the client and sends + * it to the server. + * + * Parameters : + * 1 : csp = Current client state (buffers, headers, etc...) + * + * Returns : 0 on success, anything else is an error. + * + *********************************************************************/ +static int receive_and_send_encrypted_post_data(struct client_state *csp) +{ + int content_length_known = csp->expected_client_content_length != 0; + + while (is_ssl_pending(&(csp->ssl_client_attr)) + || (content_length_known && csp->expected_client_content_length != 0)) + { + unsigned char buf[BUFFER_SIZE]; + int len; + int max_bytes_to_read = sizeof(buf); + + if (content_length_known && csp->expected_client_content_length < sizeof(buf)) + { + max_bytes_to_read = (int)csp->expected_client_content_length; + } + log_error(LOG_LEVEL_CONNECT, + "Waiting for up to %d bytes of POST data from the client.", + max_bytes_to_read); + len = ssl_recv_data(&(csp->ssl_client_attr), buf, + (unsigned)max_bytes_to_read); + if (len == -1) + { + return 1; + } + if (len == 0) + { + /* XXX: Does this actually happen? */ + break; + } + log_error(LOG_LEVEL_CONNECT, "Forwarding %d bytes of encrypted POST data", + len); + len = ssl_send_data(&(csp->ssl_server_attr), buf, (size_t)len); + if (len == -1) + { + return 1; + } + if (csp->expected_client_content_length != 0) + { + if (csp->expected_client_content_length >= len) + { + csp->expected_client_content_length -= (unsigned)len; + } + if (csp->expected_client_content_length == 0) + { + log_error(LOG_LEVEL_CONNECT, "Forwarded the last %d bytes", len); + break; + } + } + } + + log_error(LOG_LEVEL_CONNECT, "Done forwarding encrypted POST data"); + + return 0; + +} + + /********************************************************************* * * Function : send_https_request @@ -2046,7 +2142,7 @@ static int send_https_request(struct client_state *csp) * Write the client's (modified) header to the server * (along with anything else that may be in the buffer) */ - ret = ssl_send_data(&(csp->mbedtls_server_attr.ssl), + ret = ssl_send_data(&(csp->ssl_server_attr), (const unsigned char *)hdr, strlen(hdr)); freez(hdr); @@ -2056,41 +2152,44 @@ static int send_https_request(struct client_state *csp) "Failed sending encrypted request headers to: %s: %E", csp->http->hostport); mark_server_socket_tainted(csp); - close_client_and_server_ssl_connections(csp); return 1; } if (((csp->flags & CSP_FLAG_PIPELINED_REQUEST_WAITING) == 0) - && ((flushed = ssl_flush_socket(&(csp->mbedtls_server_attr.ssl), + && ((flushed = ssl_flush_socket(&(csp->ssl_server_attr), csp->client_iob)) < 0)) { log_error(LOG_LEVEL_CONNECT, "Failed sending request body to: %s: %E", csp->http->hostport); return 1; } - if (flushed != 0) + if (flushed != 0 || csp->expected_client_content_length != 0) { if (csp->expected_client_content_length != 0) { if (csp->expected_client_content_length < flushed) { log_error(LOG_LEVEL_ERROR, - "Flushed %d bytes of request body while only expecting %llu", + "Flushed %ld bytes of request body while only expecting %llu", flushed, csp->expected_client_content_length); csp->expected_client_content_length = 0; } else { log_error(LOG_LEVEL_CONNECT, - "Flushed %d bytes of request body while expecting %llu", + "Flushed %ld bytes of request body while expecting %llu", flushed, csp->expected_client_content_length); csp->expected_client_content_length -= (unsigned)flushed; + if (receive_and_send_encrypted_post_data(csp)) + { + return 1; + } } } else { log_error(LOG_LEVEL_CONNECT, - "Flushed %d bytes of request body", flushed); + "Flushed %ld bytes of request body", flushed); } } @@ -2123,14 +2222,21 @@ static jb_err receive_encrypted_request(struct client_state *csp) do { log_error(LOG_LEVEL_HEADER, "Reading encrypted headers"); - if (!data_is_available(csp->cfd, (int)csp->config->keep_alive_timeout)) + if (!is_ssl_pending(&(csp->ssl_client_attr)) && + !data_is_available(csp->cfd, csp->config->socket_timeout)) { log_error(LOG_LEVEL_CONNECT, "Socket %d timed out while waiting for client headers", csp->cfd); return JB_ERR_PARSE; } - len = ssl_recv_data(&(csp->mbedtls_client_attr.ssl), + len = ssl_recv_data(&(csp->ssl_client_attr), (unsigned char *)buf, sizeof(buf)); + if (len == 0) + { + log_error(LOG_LEVEL_CONNECT, + "Socket %d closed while waiting for client headers", csp->cfd); + return JB_ERR_PARSE; + } if (len == -1) { return JB_ERR_PARSE; @@ -2170,12 +2276,31 @@ static jb_err process_encrypted_request(struct client_state *csp) struct list header_list; struct list *headers = &header_list; + assert(csp->ssl_with_client_is_opened); + +#ifdef FEATURE_CONNECTION_KEEP_ALIVE + if (csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE) + { + csp->flags |= CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE; + } +#endif err = receive_encrypted_request(csp); if (err != JB_ERR_OK) { + if (csp->client_iob->cur == NULL || + csp->client_iob->cur == csp->client_iob->eod) + { + /* + * We did not receive any data, most likely because the + * client is done. Don't log this as a parse failure. + */ + return JB_ERR_PARSE; + } /* XXX: Also used for JB_ERR_MEMORY */ - ssl_send_data(&(csp->mbedtls_client_attr.ssl), - (const unsigned char *)CHEADER, strlen(CHEADER)); + log_error(LOG_LEVEL_ERROR, "Failed to receive encrypted request: %s", + jb_err_to_string(err)); + ssl_send_data_delayed(&(csp->ssl_client_attr), + (const unsigned char *)CHEADER, strlen(CHEADER), get_write_delay(csp)); return err; } @@ -2183,16 +2308,20 @@ static jb_err process_encrypted_request(struct client_state *csp) request_line = get_header(csp->client_iob); if (request_line == NULL) { - ssl_send_data(&(csp->mbedtls_client_attr.ssl), - (const unsigned char *)CHEADER, strlen(CHEADER)); + log_error(LOG_LEVEL_ERROR, "Failed to get the encrypted request line"); + ssl_send_data_delayed(&(csp->ssl_client_attr), + (const unsigned char *)CHEADER, strlen(CHEADER), get_write_delay(csp)); return JB_ERR_PARSE; } assert(*request_line != '\0'); if (client_protocol_is_unsupported(csp, request_line)) { - ssl_send_data(&(csp->mbedtls_client_attr.ssl), - (const unsigned char *)CHEADER, strlen(CHEADER)); + /* + * If the protocol is unsupported we're done here. + * client_protocol_is_unsupported() took care of sending + * the error response and logging the error message. + */ return JB_ERR_PARSE; } @@ -2213,8 +2342,8 @@ static jb_err process_encrypted_request(struct client_state *csp) freez(request_line); if (JB_ERR_OK != err) { - ssl_send_data(&(csp->mbedtls_client_attr.ssl), - (const unsigned char *)CHEADER, strlen(CHEADER)); + ssl_send_data_delayed(&(csp->ssl_client_attr), + (const unsigned char *)CHEADER, strlen(CHEADER), get_write_delay(csp)); /* XXX: Use correct size */ log_error(LOG_LEVEL_CLF, "%s - - [%T] \"Invalid request\" 400 0", csp->ip_addr_str); log_error(LOG_LEVEL_ERROR, @@ -2246,28 +2375,34 @@ static jb_err process_encrypted_request(struct client_state *csp) * Our attempts to get the request destination * elsewhere failed. */ - ssl_send_data(&(csp->mbedtls_client_attr.ssl), - (const unsigned char *)CHEADER, strlen(CHEADER)); + log_error(LOG_LEVEL_ERROR, + "Failed to get the encrypted request destination"); + ssl_send_data_delayed(&(csp->ssl_client_attr), + (const unsigned char *)CHEADER, strlen(CHEADER), get_write_delay(csp)); return JB_ERR_PARSE; } -#ifndef FEATURE_EXTENDED_HOST_PATTERNS /* Split the domain we just got for pattern matching */ init_domain_components(csp->http); -#endif - /* - * Determine the actions for this URL - */ -#ifdef FEATURE_TOGGLE - if (!(csp->flags & CSP_FLAG_TOGGLED_ON)) +#ifdef FEATURE_CLIENT_TAGS + /* XXX: If the headers were enlisted sooner, passing csp would do. */ + if (csp->client_address == NULL) { - /* Most compatible set of actions (i.e. none) */ - init_current_action(csp->action); + set_client_address(csp, headers); + get_tag_list_for_client(csp->client_tags, csp->client_address); } - else -#endif /* ndef FEATURE_TOGGLE */ +#endif + +#ifdef FEATURE_TOGGLE + if ((csp->flags & CSP_FLAG_TOGGLED_ON) != 0) +#endif { + /* + * Determine the actions for this request after + * clearing the ones from the previous one. + */ + free_current_action(csp->action); get_url_actions(csp, csp->http); } @@ -2291,8 +2426,8 @@ static jb_err process_encrypted_request(struct client_state *csp) err = sed_https(csp); if (JB_ERR_OK != err) { - ssl_send_data(&(csp->mbedtls_client_attr.ssl), - (const unsigned char *)CHEADER, strlen(CHEADER)); + ssl_send_data_delayed(&(csp->ssl_client_attr), + (const unsigned char *)CHEADER, strlen(CHEADER), get_write_delay(csp)); log_error(LOG_LEVEL_ERROR, "Failed to parse client request from %s.", csp->ip_addr_str); log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 400 0", @@ -2301,10 +2436,134 @@ static jb_err process_encrypted_request(struct client_state *csp) } log_error(LOG_LEVEL_HEADER, "Encrypted request processed"); + log_applied_actions(csp->action); + log_error(LOG_LEVEL_REQUEST, "https://%s%s", csp->http->hostport, + csp->http->path); return err; } + +/********************************************************************* + * + * Function : cgi_page_requested + * + * Description : Checks if a request is for an internal CGI page. + * + * Parameters : + * 1 : host = The host requested by the client. + * + * Returns : 1 if a CGI page has been requested, 0 otherwise + * + *********************************************************************/ +static int cgi_page_requested(const char *host) +{ + if ((0 == strcmpic(host, CGI_SITE_1_HOST)) + || (0 == strcmpic(host, CGI_SITE_1_HOST ".")) + || (0 == strcmpic(host, CGI_SITE_2_HOST)) + || (0 == strcmpic(host, CGI_SITE_2_HOST "."))) + { + return 1; + } + + return 0; + +} + + +#ifdef FEATURE_CONNECTION_KEEP_ALIVE +/********************************************************************* + * + * Function : continue_https_chat + * + * Description : Behaves similar to chat() but only deals with + * https-inspected requests that arrive on an already + * established connection. The first request is always + * served by chat() which is a lot more complex as it + * has to deal with forwarding settings and connection + * failures etc. + * + * If a connection to the server has already been + * opened it is reused unless the request is blocked + * or the forwarder changed. + * + * If a connection to the server has not yet been + * opened (because the previous request was crunched), + * or the forwarder changed, the connection is dropped + * so that the client retries on a fresh one. + * + * Parameters : + * 1 : csp = Current client state (buffers, headers, etc...) + * + * Returns : Nothing. + * + *********************************************************************/ +static void continue_https_chat(struct client_state *csp) +{ + const struct forward_spec *fwd; + + if (JB_ERR_OK != process_encrypted_request(csp)) + { + return; + } + + csp->requests_received_total++; + + /* + * We have an encrypted request. Check if one of the crunchers wants it. + */ + if (crunch_response_triggered(csp, crunchers_all)) + { + /* + * Yes. The client got the crunch response and we're done here. + */ + return; + } + if (csp->ssl_with_server_is_opened == 0) + { + log_error(LOG_LEVEL_CONNECT, + "Dropping the client connection on socket %d. " + "The server connection has not been established yet.", + csp->cfd); + csp->flags &= ~CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE; + return; + } + assert(csp->server_connection.sfd != JB_INVALID_SOCKET); + + fwd = forward_url(csp, csp->http); + if (!connection_destination_matches(&csp->server_connection, csp->http, fwd)) + { + log_error(LOG_LEVEL_CONNECT, + "Dropping the client connection on socket %d with " + "server socket %d connected to %s. The forwarder has changed.", + csp->cfd, csp->server_connection.sfd, csp->server_connection.host); + csp->flags &= ~CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE; + return; + } + + log_error(LOG_LEVEL_CONNECT, + "Reusing server socket %d connected to %s. Requests already sent: %u.", + csp->server_connection.sfd, csp->server_connection.host, + csp->server_connection.requests_sent_total); + + if (send_https_request(csp)) + { + /* + * Most likely the server connection timed out. We can't easily + * create a new one so simply drop the client connection without a + * error response to let the client retry. + */ + log_error(LOG_LEVEL_CONNECT, + "Dropping client connection on socket %d. " + "Forwarding the encrypted client request failed.", + csp->cfd); + return; + } + csp->server_connection.requests_sent_total++; + handle_established_connection(csp); + freez(csp->receive_buffer); +} +#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ #endif @@ -2340,19 +2599,12 @@ static void handle_established_connection(struct client_state *csp) long len = 0; /* for buffer sizes (and negative error codes) */ int buffer_and_filter_content = 0; unsigned int write_delay; -#ifdef FEATURE_HTTPS_FILTERING +#ifdef FEATURE_HTTPS_INSPECTION int ret = 0; int use_ssl_tunnel = 0; csp->dont_verify_certificate = 0; - /* - * Preset flags informing if SSL connections with server or client - * are opened or closed - */ - csp->ssl_with_server_is_opened = 0; - csp->ssl_with_client_is_opened = 0; - - if (csp->http->ssl && !(csp->action->flags & ACTION_ENABLE_HTTPS_FILTER)) + if (csp->http->ssl && !(csp->action->flags & ACTION_HTTPS_INSPECTION)) { /* Pass encrypted content without filtering. */ use_ssl_tunnel = 1; @@ -2397,15 +2649,7 @@ static void handle_established_connection(struct client_state *csp) for (;;) { #ifndef HAVE_POLL -#ifdef __OS2__ - /* - * FD_ZERO here seems to point to an errant macro which crashes. - * So do this by hand for now... - */ - memset(&rfds,0x00,sizeof(fd_set)); -#else FD_ZERO(&rfds); -#endif #ifdef FEATURE_CONNECTION_KEEP_ALIVE if (!watch_client_socket) { @@ -2444,14 +2688,14 @@ static void handle_established_connection(struct client_state *csp) { log_error(LOG_LEVEL_CONNECT, "Done reading from server. Content length: %llu as expected. " - "Bytes most recently read: %d.", + "Bytes most recently read: %ld.", byte_count, len); } else { log_error(LOG_LEVEL_CONNECT, "Done reading from server. Expected content length: %llu. " - "Actual content length: %llu. Bytes most recently read: %d.", + "Actual content length: %llu. Bytes most recently read: %ld.", csp->expected_content_length, byte_count, len); } len = 0; @@ -2463,114 +2707,62 @@ static void handle_established_connection(struct client_state *csp) } #endif /* FEATURE_CONNECTION_KEEP_ALIVE */ -#ifdef FEATURE_HTTPS_FILTERING - /* - * Test if some data from client or destination server are pending - * on TLS/SSL. We must work with them preferably. TLS/SSL data can - * be pending because of maximal fragment size. - */ - int read_ssl_server = 0; - int read_ssl_client = 0; - - if (client_use_ssl(csp)) - { - read_ssl_client = is_ssl_pending(&(csp->mbedtls_client_attr.ssl)) != 0; - } - - if (server_use_ssl(csp)) +#ifdef HAVE_POLL + poll_fds[0].fd = csp->cfd; +#ifdef FEATURE_CONNECTION_KEEP_ALIVE + if (!watch_client_socket) { - read_ssl_server = is_ssl_pending(&(csp->mbedtls_server_attr.ssl)) != 0; + /* + * Ignore incoming data, but still watch out + * for disconnects etc. These flags are always + * implied anyway but explicitly setting them + * doesn't hurt. + */ + poll_fds[0].events = POLLERR|POLLHUP; } - - if (!read_ssl_server && !read_ssl_client) + else #endif { -#ifdef HAVE_POLL - poll_fds[0].fd = csp->cfd; -#ifdef FEATURE_CONNECTION_KEEP_ALIVE - if (!watch_client_socket) - { - /* - * Ignore incoming data, but still watch out - * for disconnects etc. These flags are always - * implied anyway but explicitly setting them - * doesn't hurt. - */ - poll_fds[0].events = POLLERR|POLLHUP; - } - else -#endif - { - poll_fds[0].events = POLLIN; - } - poll_fds[1].fd = csp->server_connection.sfd; - poll_fds[1].events = POLLIN; - n = poll(poll_fds, 2, csp->config->socket_timeout * 1000); + poll_fds[0].events = POLLIN; + } + poll_fds[1].fd = csp->server_connection.sfd; + poll_fds[1].events = POLLIN; + n = poll(poll_fds, 2, csp->config->socket_timeout * 1000); #else - timeout.tv_sec = csp->config->socket_timeout; - timeout.tv_usec = 0; - n = select((int)maxfd + 1, &rfds, NULL, NULL, &timeout); + timeout.tv_sec = csp->config->socket_timeout; + timeout.tv_usec = 0; + n = select((int)maxfd + 1, &rfds, NULL, NULL, &timeout); #endif /* def HAVE_POLL */ - /*server or client not responding in timeout */ - if (n == 0) + /*server or client not responding in timeout */ + if (n == 0) + { + log_error(LOG_LEVEL_CONNECT, "Socket timeout %d reached: %s", + csp->config->socket_timeout, http->url); + if ((byte_count == 0) && (http->ssl == 0)) { - log_error(LOG_LEVEL_CONNECT, "Socket timeout %d reached: %s", - csp->config->socket_timeout, http->url); - if ((byte_count == 0) && (http->ssl == 0)) - { - send_crunch_response(csp, error_response(csp, "connection-timeout")); - } - mark_server_socket_tainted(csp); -#ifdef FEATURE_HTTPS_FILTERING - close_client_and_server_ssl_connections(csp); -#endif - return; + send_crunch_response(csp, error_response(csp, "connection-timeout")); } - else if (n < 0) - { -#ifdef HAVE_POLL - log_error(LOG_LEVEL_ERROR, "poll() failed!: %E"); -#else - log_error(LOG_LEVEL_ERROR, "select() failed!: %E"); -#endif - mark_server_socket_tainted(csp); -#ifdef FEATURE_HTTPS_FILTERING - close_client_and_server_ssl_connections(csp); + mark_server_socket_tainted(csp); +#ifdef FEATURE_HTTPS_INSPECTION + close_client_and_server_ssl_connections(csp); #endif - return; - } + return; } -#ifdef FEATURE_HTTPS_FILTERING - else + else if (n < 0) { - /* set FD if some data are pending on TLS/SSL connections */ -#ifndef HAVE_POLL - FD_ZERO(&rfds); -#endif - if (read_ssl_client) - { #ifdef HAVE_POLL - poll_fds[0].fd = csp->cfd; - poll_fds[0].events = POLLIN; + log_error(LOG_LEVEL_ERROR, "poll() failed!: %E"); #else - FD_SET(csp->cfd, &rfds); + log_error(LOG_LEVEL_ERROR, "select() failed!: %E"); #endif - n++; - } - - if (read_ssl_server) - { -#ifdef HAVE_POLL - poll_fds[1].fd = csp->server_connection.sfd; - poll_fds[1].events = POLLIN; -#else - FD_SET(csp->server_connection.sfd, &rfds); + mark_server_socket_tainted(csp); +#ifdef FEATURE_HTTPS_INSPECTION + close_client_and_server_ssl_connections(csp); #endif - n++; - } + return; } -#endif + /* * This is the body of the browser's request, * just read and write it. @@ -2641,39 +2833,45 @@ static void handle_established_connection(struct client_state *csp) assert(max_bytes_to_read <= csp->receive_buffer_size); #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ -#ifdef FEATURE_HTTPS_FILTERING - /* - * Reading data from standard or secured connection (HTTP/HTTPS) - */ +#ifdef FEATURE_HTTPS_INSPECTION if (client_use_ssl(csp)) { - /* - * Receiving HTTP request from client over TLS/SSL and sending - * it to server over TLS/SSL. - */ - len = ssl_recv_data(&(csp->mbedtls_client_attr.ssl), - (unsigned char *)csp->receive_buffer, (size_t)max_bytes_to_read); - - if (len <= 0) - { - mark_server_socket_tainted(csp); - break; - } - - ret = ssl_send_data(&(csp->mbedtls_server_attr.ssl), - (const unsigned char *)csp->receive_buffer, (size_t)len); - - if (ret < 0) + if (csp->http->status == 101) { - log_error(LOG_LEVEL_ERROR, - "Send request over TLS/SSL to: %s failed", http->host); - mark_server_socket_tainted(csp); - close_client_and_server_ssl_connections(csp); - return; + len = ssl_recv_data(&(csp->ssl_client_attr), + (unsigned char *)csp->receive_buffer, + (size_t)max_bytes_to_read); + if (len == -1) + { + log_error(LOG_LEVEL_ERROR, "Failed to receive data " + "on client socket %d for an upgraded connection", + csp->cfd); + break; + } + if (len == 0) + { + log_error(LOG_LEVEL_CONNECT, "Done receiving data " + "on client socket %d for an upgraded connection", + csp->cfd); + break; + } + byte_count += (unsigned long long)len; + len = ssl_send_data(&(csp->ssl_server_attr), + (unsigned char *)csp->receive_buffer, (size_t)len); + if (len == -1) + { + log_error(LOG_LEVEL_ERROR, "Failed to send data " + "on server socket %d for an upgraded connection", + csp->server_connection.sfd); + break; + } + continue; } + log_error(LOG_LEVEL_CONNECT, "Breaking with TLS/SSL."); + break; } else -#endif /* def FEATURE_HTTPS_FILTERING */ +#endif /* def FEATURE_HTTPS_INSPECTION */ { len = read_socket(csp->cfd, csp->receive_buffer, max_bytes_to_read); @@ -2691,7 +2889,7 @@ static void handle_established_connection(struct client_state *csp) csp->expected_client_content_length -= (unsigned)len; log_error(LOG_LEVEL_CONNECT, "Expected client content length set to %llu " - "after reading %d bytes.", + "after reading %ld bytes.", csp->expected_client_content_length, len); if (csp->expected_client_content_length == 0) { @@ -2706,9 +2904,6 @@ static void handle_established_connection(struct client_state *csp) { log_error(LOG_LEVEL_ERROR, "write to: %s failed: %E", http->host); mark_server_socket_tainted(csp); -#ifdef FEATURE_HTTPS_FILTERING - close_client_and_server_ssl_connections(csp); -#endif return; } } @@ -2743,7 +2938,7 @@ static void handle_established_connection(struct client_state *csp) log_error(LOG_LEVEL_CONNECT, "The server still wants to talk, but the client hung up on us."); mark_server_socket_tainted(csp); -#ifdef FEATURE_HTTPS_FILTERING +#ifdef FEATURE_HTTPS_INSPECTION close_client_and_server_ssl_connections(csp); #endif return; @@ -2751,13 +2946,13 @@ static void handle_established_connection(struct client_state *csp) } #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ -#ifdef FEATURE_HTTPS_FILTERING +#ifdef FEATURE_HTTPS_INSPECTION /* * Reading data from standard or secured connection (HTTP/HTTPS) */ if (server_use_ssl(csp)) { - len = ssl_recv_data(&(csp->mbedtls_server_attr.ssl), + len = ssl_recv_data(&(csp->ssl_server_attr), (unsigned char *)csp->receive_buffer, csp->receive_buffer_size); } else @@ -2772,7 +2967,7 @@ static void handle_established_connection(struct client_state *csp) log_error(LOG_LEVEL_ERROR, "read from: %s failed: %E", http->host); if ((http->ssl && (csp->fwd == NULL)) -#ifdef FEATURE_HTTPS_FILTERING +#ifdef FEATURE_HTTPS_INSPECTION && use_ssl_tunnel #endif ) @@ -2798,7 +2993,7 @@ static void handle_established_connection(struct client_state *csp) log_error(LOG_LEVEL_ERROR, "Already forwarded the original headers. " "Unable to tell the client about the problem."); mark_server_socket_tainted(csp); -#ifdef FEATURE_HTTPS_FILTERING +#ifdef FEATURE_HTTPS_INSPECTION close_client_and_server_ssl_connections(csp); #endif return; @@ -2867,7 +3062,7 @@ static void handle_established_connection(struct client_state *csp) { if (server_body || (http->ssl -#ifdef FEATURE_HTTPS_FILTERING +#ifdef FEATURE_HTTPS_INSPECTION && use_ssl_tunnel #endif )) @@ -2917,17 +3112,18 @@ static void handle_established_connection(struct client_state *csp) log_error(LOG_LEVEL_FATAL, "Out of memory parsing server header"); } -#ifdef FEATURE_HTTPS_FILTERING +#ifdef FEATURE_HTTPS_INSPECTION /* * Sending data with standard or secured connection (HTTP/HTTPS) */ if (client_use_ssl(csp)) { - if ((ssl_send_data(&(csp->mbedtls_client_attr.ssl), - (const unsigned char *)hdr, strlen(hdr)) < 0) - || (ssl_send_data(&(csp->mbedtls_client_attr.ssl), + if ((ssl_send_data_delayed(&(csp->ssl_client_attr), + (const unsigned char *)hdr, strlen(hdr), + get_write_delay(csp)) < 0) + || (ssl_send_data_delayed(&(csp->ssl_client_attr), (const unsigned char *) ((p != NULL) ? p : csp->iob->cur), - csp->content_length) < 0)) + csp->content_length, get_write_delay(csp)) < 0)) { log_error(LOG_LEVEL_ERROR, "write modified content to " "client over TLS/SSL failed"); @@ -2939,7 +3135,7 @@ static void handle_established_connection(struct client_state *csp) } } else -#endif /* def FEATURE_HTTPS_FILTERING */ +#endif /* def FEATURE_HTTPS_INSPECTION */ { if (write_socket_delayed(csp->cfd, hdr, strlen(hdr), write_delay) || write_socket_delayed(csp->cfd, ((p != NULL) ? p : csp->iob->cur), @@ -2949,9 +3145,6 @@ static void handle_established_connection(struct client_state *csp) freez(hdr); freez(p); mark_server_socket_tainted(csp); -#ifdef FEATURE_HTTPS_FILTERING - close_client_and_server_ssl_connections(csp); -#endif return; } } @@ -2984,7 +3177,7 @@ static void handle_established_connection(struct client_state *csp) * content-filtering. */ if (server_body || (http->ssl -#ifdef FEATURE_HTTPS_FILTERING +#ifdef FEATURE_HTTPS_INSPECTION && use_ssl_tunnel #endif )) @@ -3015,25 +3208,26 @@ static void handle_established_connection(struct client_state *csp) rsp = cgi_error_memory(); send_crunch_response(csp, rsp); mark_server_socket_tainted(csp); -#ifdef FEATURE_HTTPS_FILTERING +#ifdef FEATURE_HTTPS_INSPECTION close_client_and_server_ssl_connections(csp); #endif return; } hdrlen = strlen(hdr); -#ifdef FEATURE_HTTPS_FILTERING +#ifdef FEATURE_HTTPS_INSPECTION /* * Sending data with standard or secured connection (HTTP/HTTPS) */ if (client_use_ssl(csp)) { - if ((ssl_send_data(&(csp->mbedtls_client_attr.ssl), - (const unsigned char *)hdr, hdrlen) < 0) - || ((flushed = ssl_flush_socket(&(csp->mbedtls_client_attr.ssl), + if ((ssl_send_data_delayed(&(csp->ssl_client_attr), + (const unsigned char *)hdr, hdrlen, get_write_delay(csp)) < 0) + || ((flushed = ssl_flush_socket(&(csp->ssl_client_attr), csp->iob)) < 0) - || (ssl_send_data(&(csp->mbedtls_client_attr.ssl), - (const unsigned char *)csp->receive_buffer, (size_t)len) < 0)) + || (ssl_send_data_delayed(&(csp->ssl_client_attr), + (const unsigned char *)csp->receive_buffer, (size_t)len, + get_write_delay(csp)) < 0)) { log_error(LOG_LEVEL_CONNECT, "Flush header and buffers to client failed"); @@ -3044,7 +3238,7 @@ static void handle_established_connection(struct client_state *csp) } } else -#endif /* def FEATURE_HTTPS_FILTERING */ +#endif /* def FEATURE_HTTPS_INSPECTION */ { if (write_socket_delayed(csp->cfd, hdr, hdrlen, write_delay) || ((flushed = flush_iob(csp->cfd, csp->iob, write_delay)) < 0) @@ -3055,9 +3249,6 @@ static void handle_established_connection(struct client_state *csp) "Flush header and buffers to client failed: %E"); freez(hdr); mark_server_socket_tainted(csp); -#ifdef FEATURE_HTTPS_FILTERING - close_client_and_server_ssl_connections(csp); -#endif return; } } @@ -3075,14 +3266,15 @@ static void handle_established_connection(struct client_state *csp) } else { -#ifdef FEATURE_HTTPS_FILTERING +#ifdef FEATURE_HTTPS_INSPECTION /* * Sending data with standard or secured connection (HTTP/HTTPS) */ if (client_use_ssl(csp)) { - ret = ssl_send_data(&(csp->mbedtls_client_attr.ssl), - (const unsigned char *)csp->receive_buffer, (size_t)len); + ret = ssl_send_data_delayed(&(csp->ssl_client_attr), + (const unsigned char *)csp->receive_buffer, (size_t)len, + get_write_delay(csp)); if (ret < 0) { log_error(LOG_LEVEL_ERROR, @@ -3093,16 +3285,13 @@ static void handle_established_connection(struct client_state *csp) } } else -#endif /* def FEATURE_HTTPS_FILTERING */ +#endif /* def FEATURE_HTTPS_INSPECTION */ { if (write_socket_delayed(csp->cfd, csp->receive_buffer, (size_t)len, write_delay)) { log_error(LOG_LEVEL_ERROR, "write to client failed: %E"); mark_server_socket_tainted(csp); -#ifdef FEATURE_HTTPS_FILTERING - close_client_and_server_ssl_connections(csp); -#endif return; } } @@ -3123,7 +3312,7 @@ static void handle_established_connection(struct client_state *csp) rsp = cgi_error_memory(); send_crunch_response(csp, rsp); mark_server_socket_tainted(csp); -#ifdef FEATURE_HTTPS_FILTERING +#ifdef FEATURE_HTTPS_INSPECTION close_client_and_server_ssl_connections(csp); #endif return; @@ -3143,25 +3332,25 @@ static void handle_established_connection(struct client_state *csp) "Applying the MS IIS5 hack didn't help."); log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 502 0", csp->ip_addr_str, http->cmd); -#ifdef FEATURE_HTTPS_FILTERING +#ifdef FEATURE_HTTPS_INSPECTION /* * Sending data with standard or secured connection (HTTP/HTTPS) */ if (client_use_ssl(csp)) { - ssl_send_data(&(csp->mbedtls_client_attr.ssl), + ssl_send_data_delayed(&(csp->ssl_client_attr), (const unsigned char *)INVALID_SERVER_HEADERS_RESPONSE, - strlen(INVALID_SERVER_HEADERS_RESPONSE)); + strlen(INVALID_SERVER_HEADERS_RESPONSE), get_write_delay(csp)); } else -#endif /* def FEATURE_HTTPS_FILTERING */ +#endif /* def FEATURE_HTTPS_INSPECTION */ { write_socket_delayed(csp->cfd, INVALID_SERVER_HEADERS_RESPONSE, strlen(INVALID_SERVER_HEADERS_RESPONSE), write_delay); } mark_server_socket_tainted(csp); -#ifdef FEATURE_HTTPS_FILTERING +#ifdef FEATURE_HTTPS_INSPECTION close_client_and_server_ssl_connections(csp); #endif return; @@ -3174,7 +3363,7 @@ static void handle_established_connection(struct client_state *csp) */ log_error(LOG_LEVEL_CONNECT, "Continuing buffering server headers from socket %d. " - "Bytes most recently read: %d.", csp->cfd, len); + "Bytes most recently read: %ld.", csp->cfd, len); continue; } } @@ -3209,7 +3398,7 @@ static void handle_established_connection(struct client_state *csp) } free_http_request(http); mark_server_socket_tainted(csp); -#ifdef FEATURE_HTTPS_FILTERING +#ifdef FEATURE_HTTPS_INSPECTION close_client_and_server_ssl_connections(csp); #endif return; @@ -3237,25 +3426,26 @@ static void handle_established_connection(struct client_state *csp) csp->headers->first->str); log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 502 0", csp->ip_addr_str, http->cmd); -#ifdef FEATURE_HTTPS_FILTERING +#ifdef FEATURE_HTTPS_INSPECTION /* * Sending data with standard or secured connection (HTTP/HTTPS) */ if (client_use_ssl(csp)) { - ssl_send_data(&(csp->mbedtls_client_attr.ssl), + ssl_send_data_delayed(&(csp->ssl_client_attr), (const unsigned char *)INVALID_SERVER_HEADERS_RESPONSE, - strlen(INVALID_SERVER_HEADERS_RESPONSE)); + strlen(INVALID_SERVER_HEADERS_RESPONSE), + get_write_delay(csp)); } else -#endif /* def FEATURE_HTTPS_FILTERING */ +#endif /* def FEATURE_HTTPS_INSPECTION */ { write_socket_delayed(csp->cfd, INVALID_SERVER_HEADERS_RESPONSE, strlen(INVALID_SERVER_HEADERS_RESPONSE), write_delay); } free_http_request(http); mark_server_socket_tainted(csp); -#ifdef FEATURE_HTTPS_FILTERING +#ifdef FEATURE_HTTPS_INSPECTION close_client_and_server_ssl_connections(csp); #endif return; @@ -3269,15 +3459,16 @@ static void handle_established_connection(struct client_state *csp) { log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 502 0", csp->ip_addr_str, http->cmd); -#ifdef FEATURE_HTTPS_FILTERING +#ifdef FEATURE_HTTPS_INSPECTION /* * Sending data with standard or secured connection (HTTP/HTTPS) */ if (client_use_ssl(csp)) { - ssl_send_data(&(csp->mbedtls_client_attr.ssl), + ssl_send_data_delayed(&(csp->ssl_client_attr), (const unsigned char *)INVALID_SERVER_HEADERS_RESPONSE, - strlen(INVALID_SERVER_HEADERS_RESPONSE)); + strlen(INVALID_SERVER_HEADERS_RESPONSE), + get_write_delay(csp)); } else #endif @@ -3287,7 +3478,7 @@ static void handle_established_connection(struct client_state *csp) } free_http_request(http); mark_server_socket_tainted(csp); -#ifdef FEATURE_HTTPS_FILTERING +#ifdef FEATURE_HTTPS_INSPECTION close_client_and_server_ssl_connections(csp); #endif return; @@ -3324,7 +3515,7 @@ static void handle_established_connection(struct client_state *csp) */ freez(hdr); mark_server_socket_tainted(csp); -#ifdef FEATURE_HTTPS_FILTERING +#ifdef FEATURE_HTTPS_INSPECTION close_client_and_server_ssl_connections(csp); #endif return; @@ -3341,12 +3532,13 @@ static void handle_established_connection(struct client_state *csp) * may be in the buffer). Use standard or secured * connection. */ -#ifdef FEATURE_HTTPS_FILTERING +#ifdef FEATURE_HTTPS_INSPECTION if (client_use_ssl(csp)) { - if ((ssl_send_data(&(csp->mbedtls_client_attr.ssl), - (const unsigned char *)hdr, strlen(hdr)) < 0) - || (len = ssl_flush_socket(&(csp->mbedtls_client_attr.ssl), + if ((ssl_send_data_delayed(&(csp->ssl_client_attr), + (const unsigned char *)hdr, strlen(hdr), + get_write_delay(csp)) < 0) + || (len = ssl_flush_socket(&(csp->ssl_client_attr), csp->iob) < 0)) { log_error(LOG_LEVEL_CONNECT, "Write header to client failed"); @@ -3357,14 +3549,14 @@ static void handle_established_connection(struct client_state *csp) */ freez(hdr); mark_server_socket_tainted(csp); -#ifdef FEATURE_HTTPS_FILTERING +#ifdef FEATURE_HTTPS_INSPECTION close_client_and_server_ssl_connections(csp); #endif return; } } else -#endif /* def FEATURE_HTTPS_FILTERING */ +#endif /* def FEATURE_HTTPS_INSPECTION */ { if (write_socket_delayed(csp->cfd, hdr, strlen(hdr), write_delay) || ((len = flush_iob(csp->cfd, csp->iob, write_delay)) < 0)) @@ -3377,9 +3569,6 @@ static void handle_established_connection(struct client_state *csp) */ freez(hdr); mark_server_socket_tainted(csp); -#ifdef FEATURE_HTTPS_FILTERING - close_client_and_server_ssl_connections(csp); -#endif return; } } @@ -3402,24 +3591,25 @@ static void handle_established_connection(struct client_state *csp) "Applying the MS IIS5 hack didn't help."); log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 502 0", csp->ip_addr_str, http->cmd); -#ifdef FEATURE_HTTPS_FILTERING +#ifdef FEATURE_HTTPS_INSPECTION /* * Sending data with standard or secured connection (HTTP/HTTPS) */ if (client_use_ssl(csp)) { - ssl_send_data(&(csp->mbedtls_client_attr.ssl), + ssl_send_data_delayed(&(csp->ssl_client_attr), (const unsigned char *)INVALID_SERVER_HEADERS_RESPONSE, - strlen(INVALID_SERVER_HEADERS_RESPONSE)); + strlen(INVALID_SERVER_HEADERS_RESPONSE), + get_write_delay(csp)); } else -#endif /* def FEATURE_HTTPS_FILTERING */ +#endif /* def FEATURE_HTTPS_INSPECTION */ { write_socket_delayed(csp->cfd, INVALID_SERVER_HEADERS_RESPONSE, strlen(INVALID_SERVER_HEADERS_RESPONSE), write_delay); } mark_server_socket_tainted(csp); -#ifdef FEATURE_HTTPS_FILTERING +#ifdef FEATURE_HTTPS_INSPECTION close_client_and_server_ssl_connections(csp); #endif return; @@ -3428,14 +3618,12 @@ static void handle_established_connection(struct client_state *csp) continue; } mark_server_socket_tainted(csp); -#ifdef FEATURE_HTTPS_FILTERING +#ifdef FEATURE_HTTPS_INSPECTION close_client_and_server_ssl_connections(csp); #endif return; /* huh? we should never get here */ } -#ifdef FEATURE_HTTPS_FILTERING - close_client_and_server_ssl_connections(csp); -#endif + if (csp->content_length == 0) { /* @@ -3456,9 +3644,19 @@ static void handle_established_connection(struct client_state *csp) } #endif - log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 200 %llu", - csp->ip_addr_str, http->ocmd, csp->content_length); - +#ifdef FEATURE_HTTPS_INSPECTION + if (client_use_ssl(csp)) + { + log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s https://%s%s %s\" 200 %llu", + csp->ip_addr_str, http->gpc, http->hostport, http->path, + http->version, csp->content_length); + } + else +#endif + { + log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 200 %llu", + csp->ip_addr_str, http->ocmd, csp->content_length); + } csp->server_connection.timestamp = time(NULL); } @@ -3493,7 +3691,7 @@ static void chat(struct client_state *csp) struct http_request *http; /* Skeleton for HTTP response, if we should intercept the request */ struct http_response *rsp; -#ifdef FEATURE_HTTPS_FILTERING +#ifdef FEATURE_HTTPS_INSPECTION int use_ssl_tunnel = 0; #endif @@ -3510,19 +3708,14 @@ static void chat(struct client_state *csp) /* decide how to route the HTTP request */ fwd = forward_url(csp, http); - if (NULL == fwd) - { - log_error(LOG_LEVEL_FATAL, "gateway spec is NULL!?!? This can't happen!"); - /* Never get here - LOG_LEVEL_FATAL causes program exit */ - return; - } -#ifdef FEATURE_HTTPS_FILTERING +#ifdef FEATURE_HTTPS_INSPECTION /* * Setting flags to use old solution with SSL tunnel and to disable - * certificates verification. + * certificate verification. */ - if (csp->http->ssl && !(csp->action->flags & ACTION_ENABLE_HTTPS_FILTER)) + if (csp->http->ssl && !(csp->action->flags & ACTION_HTTPS_INSPECTION) + && !cgi_page_requested(csp->http->host)) { use_ssl_tunnel = 1; } @@ -3574,7 +3767,7 @@ static void chat(struct client_state *csp) * */ -#ifdef FEATURE_HTTPS_FILTERING +#ifdef FEATURE_HTTPS_INSPECTION /* * Presetting SSL client and server flags */ @@ -3590,6 +3783,18 @@ static void chat(struct client_state *csp) } #endif +#ifdef FEATURE_HTTPS_INSPECTION + /* + * Log the request unless we're https inspecting + * in which case we don't have the path yet and + * will log the request later. + */ + if (!client_use_ssl(csp)) +#endif + { + log_error(LOG_LEVEL_REQUEST, "%s%s", http->hostport, http->path); + } + if (http->ssl && connect_port_is_forbidden(csp)) { const char *acceptable_connect_ports = @@ -3600,7 +3805,7 @@ static void chat(struct client_state *csp) csp->ip_addr_str, acceptable_connect_ports, csp->http->hostport); csp->action->flags |= ACTION_BLOCK; http->ssl = 0; -#ifdef FEATURE_HTTPS_FILTERING +#ifdef FEATURE_HTTPS_INSPECTION http->client_ssl = 0; http->server_ssl = 0; #endif @@ -3611,9 +3816,16 @@ static void chat(struct client_state *csp) build_request_line(csp, fwd, &csp->headers->first->str); /* - * We have a request. Check if one of the crunchers wants it. + * We have a request. Check if one of the crunchers wants it + * unless the client wants to use TLS/SSL in which case we + * haven't setup the TLS context yet and will send the crunch + * response later. */ - if (crunch_response_triggered(csp, crunchers_all)) + if ( +#ifdef FEATURE_HTTPS_INSPECTION + !client_use_ssl(csp) && +#endif + crunch_response_triggered(csp, crunchers_all)) { /* * Yes. The client got the crunch response and we're done here. @@ -3622,8 +3834,6 @@ static void chat(struct client_state *csp) } log_applied_actions(csp->action); - log_error(LOG_LEVEL_GPC, "%s%s", http->hostport, http->path); - if (fwd->forward_host) { log_error(LOG_LEVEL_CONNECT, "via [%s]:%d to: %s", @@ -3651,7 +3861,11 @@ static void chat(struct client_state *csp) if (csp->server_connection.sfd != JB_INVALID_SOCKET) { #ifdef FEATURE_CONNECTION_SHARING - if (csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_SHARING) + if (csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_SHARING +#ifdef FEATURE_HTTPS_INSPECTION + && !server_use_ssl(csp) +#endif + ) { remember_connection(&csp->server_connection); } @@ -3667,42 +3881,34 @@ static void chat(struct client_state *csp) mark_connection_closed(&csp->server_connection); } #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ -#ifdef FEATURE_HTTPS_FILTERING +#ifdef FEATURE_HTTPS_INSPECTION if (http->ssl && !use_ssl_tunnel) { int ret; /* - * Creating an SSL proxy. If forwarding is disabled, we must send - * CSUCCEED mesage to client. Then TLS/SSL connection with client - * is created. + * Creating a SSL proxy. + * + * By sending the CSUCCEED message we're lying to the client as + * the connection hasn't actually been established yet. We don't + * establish the connection until we have seen and parsed the + * encrypted client headers. */ - - if (fwd->forward_host == NULL) + if (write_socket_delayed(csp->cfd, CSUCCEED, + strlen(CSUCCEED), get_write_delay(csp)) != 0) { - /* - * We're lying to the client as the connection hasn't actually - * been established yet. We don't establish the connection until - * we have seen and parsed the encrypted client headers. - */ - if (write_socket_delayed(csp->cfd, CSUCCEED, - strlen(CSUCCEED), get_write_delay(csp)) != 0) - { - log_error(LOG_LEVEL_ERROR, "Sending SUCCEED to client failed"); - return; - } + log_error(LOG_LEVEL_ERROR, "Sending SUCCEED to client failed"); + return; } ret = create_client_ssl_connection(csp); if (ret != 0) { log_error(LOG_LEVEL_ERROR, - "Can't open secure connection with client"); - close_client_ssl_connection(csp); /* XXX: Is this needed? */ + "Failed to open a secure connection with the client"); return; } if (JB_ERR_OK != process_encrypted_request(csp)) { - log_error(LOG_LEVEL_ERROR, "Failed to parse encrypted request."); close_client_ssl_connection(csp); return; } @@ -3716,7 +3922,6 @@ static void chat(struct client_state *csp) /* * Yes. The client got the crunch response and we're done here. */ - close_client_ssl_connection(csp); return; } } @@ -3760,13 +3965,16 @@ static void chat(struct client_state *csp) * client body in the buffer (if there is one) and to * continue parsing the bytes that follow. */ +#ifdef FEATURE_HTTPS_INSPECTION + close_client_ssl_connection(csp); +#endif drain_and_close_socket(csp->cfd); csp->cfd = JB_INVALID_SOCKET; return; } -#ifdef FEATURE_HTTPS_FILTERING +#ifdef FEATURE_HTTPS_INSPECTION /* * Creating TLS/SSL connections with destination server or parent * proxy. If forwarding is enabled, we must send client request to @@ -3825,84 +4033,61 @@ static void chat(struct client_state *csp) } /* - * Test if connection with destination server was established - * successfully by parent proxy. Then we can send response to - * the client and continue or stop. + * Test if the connection to the destination server was + * established successfully by the parent proxy. */ if (!tunnel_established_successfully(server_response, (unsigned int)len)) { - log_error(LOG_LEVEL_ERROR, "Forwarder hasn't established " - "connection with destination server."); - - write_socket(csp->cfd, server_response, (size_t)len); - mark_server_socket_tainted(csp); - close_client_ssl_connection(csp); - return; - } - - /* - * Parent proxy has established connection with destination server. - * Now we must create TLS/SSL connection with parent proxy. - */ - ret = create_server_ssl_connection(csp); - - /* - * If TLS/SSL connection wasn't created and invalid certificate - * wasn't detected, we can interrupt this fuction. Otherwise, we - * must inform the client about invalid server certificate. - */ - if (ret != 0 - && (csp->server_cert_verification_result == SSL_CERT_NOT_VERIFIED - || csp->server_cert_verification_result == SSL_CERT_VALID)) - { + log_error(LOG_LEVEL_ERROR, + "The forwarder %s failed to establish a connection with %s", + fwd->forward_host, http->host); rsp = error_response(csp, "connect-failed"); if (rsp) { send_crunch_response(csp, rsp); } + mark_server_socket_tainted(csp); + close_client_ssl_connection(csp); return; } + } /* -END- if (fwd->forward_host != NULL) */ - /* - * TLS/SSL connection with parent proxy is established, we can - * inform client about success. - */ - ret = write_socket(csp->cfd, server_response, (size_t)len); - if (ret != 0) + /* + * We can now create the TLS/SSL connection with the destination server. + */ + int ret = create_server_ssl_connection(csp); + if (ret != 0) + { + if (csp->server_cert_verification_result != SSL_CERT_VALID && + csp->server_cert_verification_result != SSL_CERT_NOT_VERIFIED) { - log_error(LOG_LEVEL_ERROR, - "Sending parent proxy response to client failed"); - mark_server_socket_tainted(csp); - close_client_ssl_connection(csp); + /* + * If the server certificate is invalid, we must inform + * the client and then close connection to the client. + */ + ssl_send_certificate_error(csp); + close_client_and_server_ssl_connections(csp); return; } - }/* -END- if (fwd->forward_host != NULL) */ - else - { - /* - * Parent proxy is not used, we can just create TLS/SSL connection - * with destination server - */ - int ret = create_server_ssl_connection(csp); - /* - * If TLS/SSL connection wasn't created and invalid certificate - * wasn't detected, we can interrupt this function. Otherwise, we - * must inform client about invalid server certificate. - */ - if (ret != 0 - && (csp->server_cert_verification_result == SSL_CERT_NOT_VERIFIED - || csp->server_cert_verification_result == SSL_CERT_VALID)) + if (csp->server_cert_verification_result == SSL_CERT_NOT_VERIFIED + || csp->server_cert_verification_result == SSL_CERT_VALID) { + /* + * The TLS/SSL connection wasn't created but an invalid + * certificate wasn't detected. Report it as connection + * failure. + */ rsp = error_response(csp, "connect-failed"); if (rsp) { send_crunch_response(csp, rsp); } + close_client_and_server_ssl_connections(csp); return; } } }/* -END- if (http->ssl) */ -#endif /* def FEATURE_HTTPS_FILTERING */ +#endif /* def FEATURE_HTTPS_INSPECTION */ #ifdef FEATURE_CONNECTION_KEEP_ALIVE save_connection_destination(csp->server_connection.sfd, @@ -3920,7 +4105,7 @@ static void chat(struct client_state *csp) assert(csp->headers->last == NULL); } else if (http->ssl == 0 || (fwd->forward_host -#ifdef FEATURE_HTTPS_FILTERING +#ifdef FEATURE_HTTPS_INSPECTION && use_ssl_tunnel #endif )) @@ -3941,7 +4126,7 @@ static void chat(struct client_state *csp) * Using old solution with SSL tunnel or new solution with SSL proxy */ list_remove_all(csp->headers); -#ifdef FEATURE_HTTPS_FILTERING +#ifdef FEATURE_HTTPS_INSPECTION if (use_ssl_tunnel) #endif { @@ -3956,14 +4141,16 @@ static void chat(struct client_state *csp) return; } } -#ifdef FEATURE_HTTPS_FILTERING +#ifdef FEATURE_HTTPS_INSPECTION else { /* - * If server certificate is invalid, we must inform client and then - * close connection with client. + * If server certificate has been verified and is invalid, + * we must inform the client and then close the connection + * with client and server. */ - if (csp->server_cert_verification_result != SSL_CERT_VALID) + if (csp->server_cert_verification_result != SSL_CERT_VALID && + csp->server_cert_verification_result != SSL_CERT_NOT_VERIFIED) { ssl_send_certificate_error(csp); close_client_and_server_ssl_connections(csp); @@ -3974,13 +4161,13 @@ static void chat(struct client_state *csp) rsp = error_response(csp, "connect-failed"); if (rsp) { - send_crunch_response(csp, rsp); /* XXX: use ssl*/ + send_crunch_response(csp, rsp); } close_client_and_server_ssl_connections(csp); return; } } -#endif /* def FEATURE_HTTPS_FILTERING */ +#endif /* def FEATURE_HTTPS_INSPECTION */ clear_iob(csp->client_iob); }/* -END- else ... if (http->ssl == 1) */ @@ -4015,7 +4202,7 @@ extern int fuzz_server_response(struct client_state *csp, char *fuzz_input_file) if (strcmp(fuzz_input_file, "-") == 0) { - /* XXX: Doesn'T work yet. */ + /* XXX: Doesn't work yet. */ csp->server_connection.sfd = 0; } else @@ -4080,6 +4267,9 @@ static void prepare_csp_for_next_request(struct client_state *csp) freez(csp->error_message); free_http_request(csp->http); destroy_list(csp->headers); +#ifdef FEATURE_HTTPS_INSPECTION + destroy_list(csp->https_headers); +#endif destroy_list(csp->tags); #ifdef FEATURE_CLIENT_TAGS destroy_list(csp->client_tags); @@ -4108,7 +4298,7 @@ static void prepare_csp_for_next_request(struct client_state *csp) assert(bytes_to_shift > 0); assert(data_length > 0); - log_error(LOG_LEVEL_CONNECT, "Shifting %d pipelined bytes by %d bytes", + log_error(LOG_LEVEL_CONNECT, "Shifting %lu pipelined bytes by %ld bytes", data_length, bytes_to_shift); memmove(csp->client_iob->buf, csp->client_iob->cur, data_length); csp->client_iob->cur = csp->client_iob->buf; @@ -4164,7 +4354,16 @@ static void serve(struct client_state *csp) { unsigned int latency; - chat(csp); +#ifdef FEATURE_HTTPS_INSPECTION + if (continue_chatting && client_use_ssl(csp)) + { + continue_https_chat(csp); + } + else +#endif + { + chat(csp); + } /* * If the request has been crunched, @@ -4204,7 +4403,7 @@ static void serve(struct client_state *csp) { log_error(LOG_LEVEL_CONNECT, "Closing server socket %d connected to %s. " - "Keep-alive %u. Tainted: %u. Socket alive %u. Timeout: %u.", + "Keep-alive: %u. Tainted: %u. Socket alive: %u. Timeout: %u.", csp->server_connection.sfd, csp->server_connection.host, 0 != (csp->flags & CSP_FLAG_SERVER_CONNECTION_KEEP_ALIVE), 0 != (csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED), @@ -4216,6 +4415,9 @@ static void serve(struct client_state *csp) forget_connection(csp->server_connection.sfd); } #endif /* def FEATURE_CONNECTION_SHARING */ +#ifdef FEATURE_HTTPS_INSPECTION + close_server_ssl_connection(csp); +#endif close_socket(csp->server_connection.sfd); mark_connection_closed(&csp->server_connection); } @@ -4226,6 +4428,15 @@ static void serve(struct client_state *csp) continue_chatting = 0; config_file_change_detected = 1; } +#ifdef FEATURE_HTTPS_INSPECTION + if (continue_chatting && client_use_ssl(csp) && + csp->ssl_with_client_is_opened == 0) + { + continue_chatting = 0; + log_error(LOG_LEVEL_CONNECT, "Client socket %d is no longer usable. " + "The TLS session has been terminated.", csp->cfd); + } +#endif if (continue_chatting) { @@ -4261,8 +4472,8 @@ static void serve(struct client_state *csp) && socket_is_still_alive(csp->cfd)) { log_error(LOG_LEVEL_CONNECT, - "Client request %u arrived in time on socket %d.", - csp->requests_received_total+1, csp->cfd); + "Data arrived in time on client socket %d. Requests so far: %u", + csp->cfd, csp->requests_received_total); prepare_csp_for_next_request(csp); } else @@ -4270,7 +4481,11 @@ static void serve(struct client_state *csp) #ifdef FEATURE_CONNECTION_SHARING if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_SHARING) && (csp->server_connection.sfd != JB_INVALID_SOCKET) - && (socket_is_still_alive(csp->server_connection.sfd))) + && (socket_is_still_alive(csp->server_connection.sfd)) +#ifdef FEATURE_HTTPS_INSPECTION + && !server_use_ssl(csp) +#endif + ) { time_t time_open = time(NULL) - csp->server_connection.timestamp; @@ -4317,6 +4532,20 @@ static void serve(struct client_state *csp) chat(csp); #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ + if (csp->cfd != JB_INVALID_SOCKET) + { + log_error(LOG_LEVEL_CONNECT, "Closing client socket %d. " + "Keep-alive: %u. Socket alive: %u. Data available: %u. " + "Configuration file change detected: %u. Requests received: %u.", + csp->cfd, 0 != (csp->flags & CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE), + socket_is_still_alive(csp->cfd), data_is_available(csp->cfd, 0), + config_file_change_detected, csp->requests_received_total); +#ifdef FEATURE_HTTPS_INSPECTION + close_client_ssl_connection(csp); +#endif + drain_and_close_socket(csp->cfd); + } + if (csp->server_connection.sfd != JB_INVALID_SOCKET) { #ifdef FEATURE_CONNECTION_SHARING @@ -4325,6 +4554,11 @@ static void serve(struct client_state *csp) forget_connection(csp->server_connection.sfd); } #endif /* def FEATURE_CONNECTION_SHARING */ + +#ifdef FEATURE_HTTPS_INSPECTION + close_server_ssl_connection(csp); +#endif /* def FEATURE_HTTPS_INSPECTION */ + close_socket(csp->server_connection.sfd); } @@ -4332,17 +4566,6 @@ static void serve(struct client_state *csp) mark_connection_closed(&csp->server_connection); #endif - if (csp->cfd != JB_INVALID_SOCKET) - { - log_error(LOG_LEVEL_CONNECT, "Closing client socket %d. " - "Keep-alive: %u. Socket alive: %u. Data available: %u. " - "Configuration file change detected: %u. Requests received: %u.", - csp->cfd, 0 != (csp->flags & CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE), - socket_is_still_alive(csp->cfd), data_is_available(csp->cfd, 0), - config_file_change_detected, csp->requests_received_total); - drain_and_close_socket(csp->cfd); - } - free_csp_resources(csp); csp->flags &= ~CSP_FLAG_ACTIVE; @@ -4519,17 +4742,10 @@ static void initialize_mutexes(void) * Prepare global mutex semaphores */ -#ifdef LIMIT_MUTEX_NUMBER - int i = 0; - for (i = 0; i < 32; i++) -#else - int i = 0; - for (i = 0; i < 65536; i++) -#endif /* LIMIT_MUTEX_NUMBER */ - { - privoxy_mutex_init(&(certificates_mutexes[i])); - } - privoxy_mutex_init(&rng_mutex); +#ifdef FEATURE_HTTPS_INSPECTION + privoxy_mutex_init(&certificate_mutex); + privoxy_mutex_init(&ssl_init_mutex); +#endif privoxy_mutex_init(&log_mutex); privoxy_mutex_init(&log_init_mutex); @@ -4540,6 +4756,10 @@ static void initialize_mutexes(void) #ifdef FEATURE_CLIENT_TAGS privoxy_mutex_init(&client_tags_mutex); #endif +#ifdef FEATURE_EXTENDED_STATISTICS + privoxy_mutex_init(&filter_statistics_mutex); + privoxy_mutex_init(&block_statistics_mutex); +#endif /* * XXX: The assumptions below are a bit naive @@ -4829,7 +5049,7 @@ int main(int argc, char **argv) * are handled when and where they occur without relying * on a signal. */ -#if !defined(_WIN32) && !defined(__OS2__) +#if !defined(_WIN32) { int idx; const int catched_signals[] = { SIGTERM, SIGINT, SIGHUP }; @@ -5291,7 +5511,7 @@ static void listen_loop(void) for (;;) #endif { -#if !defined(FEATURE_PTHREAD) && !defined(_WIN32) && !defined(__BEOS__) && !defined(__OS2__) +#if !defined(FEATURE_PTHREAD) && !defined(_WIN32) && !defined(__BEOS__) while (waitpid(-1, NULL, WNOHANG) > 0) { /* zombie children */ @@ -5321,7 +5541,7 @@ static void listen_loop(void) csp = &csp_list->csp; log_error(LOG_LEVEL_CONNECT, - "Waiting for the next client connection. Currently active threads: %d", + "Waiting for the next client connection. Currently active threads: %u", active_threads); /* @@ -5420,10 +5640,11 @@ static void listen_loop(void) #define SELECTED_ONE_OPTION { pthread_t the_thread; + int ret; - errno = pthread_create(&the_thread, &attrs, + ret = pthread_create(&the_thread, &attrs, (void * (*)(void *))serve, csp); - child_id = errno ? -1 : 0; + child_id = ret ? -1 : 0; } #endif @@ -5435,15 +5656,6 @@ static void listen_loop(void) csp); #endif -#if defined(__OS2__) && !defined(SELECTED_ONE_OPTION) -#define SELECTED_ONE_OPTION - child_id = _beginthread( - (void(* _Optlink)(void*))serve, - NULL, - 64 * 1024, - csp); -#endif - #if defined(__BEOS__) && !defined(SELECTED_ONE_OPTION) #define SELECTED_ONE_OPTION { @@ -5546,7 +5758,7 @@ static void listen_loop(void) * XXX: If you assume ... */ log_error(LOG_LEVEL_ERROR, - "Unable to take any additional connections: %E. Active threads: %d", + "Unable to take any additional connections: %E. Active threads: %u", active_threads); write_socket_delayed(csp->cfd, TOO_MANY_CONNECTIONS_RESPONSE, strlen(TOO_MANY_CONNECTIONS_RESPONSE), get_write_delay(csp)); @@ -5566,18 +5778,14 @@ static void listen_loop(void) /* NOTREACHED unless FEATURE_GRACEFUL_TERMINATION is defined */ -#ifdef FEATURE_HTTPS_FILTERING +#ifdef FEATURE_HTTPS_INSPECTION /* Clean up. Aim: free all memory (no leaks) */ - if (rng_seeded == 1) - { - mbedtls_ctr_drbg_free(&ctr_drbg); - mbedtls_entropy_free(&entropy); - } + ssl_release(); #endif #ifdef FEATURE_GRACEFUL_TERMINATION - log_error(LOG_LEVEL_ERROR, "Graceful termination requested"); + log_error(LOG_LEVEL_INFO, "Graceful termination requested"); unload_current_config_file(); unload_current_actions_file();