X-Git-Url: http://www.privoxy.org/gitweb/?p=privoxy.git;a=blobdiff_plain;f=jcc.c;h=3129bab450eb1f6d69e3ce17aeb18bb63bc95e8d;hp=c30e75d1d4c9bffdf3c8905662a14b3e950d1ace;hb=bce0c44ff68888e53be6e0f986cb46c39ce8e3a5;hpb=2111876638f912fa7be56a3df315efbbfde91f38 diff --git a/jcc.c b/jcc.c index c30e75d1..3129bab4 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-2018 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 @@ -112,7 +112,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" @@ -150,7 +150,7 @@ static int client_protocol_is_unsupported(const struct client_state *csp, char * 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); -static void send_crunch_response(const struct client_state *csp, struct http_response *rsp); +static void send_crunch_response(struct client_state *csp, struct http_response *rsp); static char *get_request_line(struct client_state *csp); static jb_err receive_client_request(struct client_state *csp); static jb_err parse_client_request(struct client_state *csp); @@ -193,12 +193,8 @@ 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; +privoxy_mutex_t certificate_mutex; +privoxy_mutex_t rng_mutex; #ifdef FEATURE_EXTERNAL_FILTERS privoxy_mutex_t external_filter_mutex; @@ -809,7 +805,7 @@ static void log_applied_actions(const struct current_action_spec *actions) * Returns : Nothing. * *********************************************************************/ -static void send_crunch_response(const struct client_state *csp, struct http_response *rsp) +static void send_crunch_response(struct client_state *csp, struct http_response *rsp) { const struct http_request *http = csp->http; char status_code[4]; @@ -844,13 +840,33 @@ static void send_crunch_response(const struct client_state *csp, struct http_res csp->ip_addr_str, http->ocmd, status_code, rsp->content_length); /* Write the answer to the client */ - if (write_socket_delayed(csp->cfd, rsp->head, rsp->head_length, get_write_delay(csp)) - || write_socket_delayed(csp->cfd, rsp->body, rsp->content_length, get_write_delay(csp))) +#ifdef FEATURE_HTTPS_INSPECTION + if (client_use_ssl(csp)) { - /* 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: %E", - http->url, csp->cfd); + 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)) + { + /* 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); + } + } + else +#endif + { + if (write_socket_delayed(csp->cfd, rsp->head, rsp->head_length, + get_write_delay(csp)) + || write_socket_delayed(csp->cfd, rsp->body, rsp->content_length, + get_write_delay(csp))) + { + /* 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: %E", + http->url, csp->cfd); + } } /* Clean up and return */ @@ -1994,6 +2010,351 @@ static int send_http_request(struct client_state *csp) } +#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 jb_err receive_and_send_encrypted_post_data(struct client_state *csp) +{ + unsigned char buf[BUFFER_SIZE]; + int len; + + while (is_ssl_pending(&(csp->mbedtls_client_attr.ssl))) + { + len = ssl_recv_data(&(csp->mbedtls_client_attr.ssl), buf, sizeof(buf)); + if (len == -1) + { + return 1; + } + if (len == 0) + { + /* XXX: Does this actually happen? */ + break; + } + log_error(LOG_LEVEL_HEADER, "Forwarding %d bytes of encrypted POST data", + len); + len = ssl_send_data(&(csp->mbedtls_server_attr.ssl), 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; + } + } + } + + log_error(LOG_LEVEL_HEADER, "Done forwarding encrypted POST data"); + + return 0; + +} + + +/********************************************************************* + * + * Function : send_https_request + * + * Description : Sends the HTTP headers from the client request + * and all the body data that has already been received. + * + * Parameters : + * 1 : csp = Current client state (buffers, headers, etc...) + * + * Returns : 0 on success, anything else is an error. + * + *********************************************************************/ +static int send_https_request(struct client_state *csp) +{ + char *hdr; + int ret; + long flushed = 0; + + hdr = list_to_text(csp->https_headers); + if (hdr == NULL) + { + /* FIXME Should handle error properly */ + log_error(LOG_LEVEL_FATAL, "Out of memory parsing client header"); + } + list_remove_all(csp->https_headers); + + /* + * 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), + (const unsigned char *)hdr, strlen(hdr)); + freez(hdr); + + if (ret < 0) + { + log_error(LOG_LEVEL_CONNECT, + "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), + 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 (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, 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, 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); + } + } + + log_error(LOG_LEVEL_CONNECT, "Encrypted request sent"); + + return 0; + +} + + +/********************************************************************* + * + * Function : receive_encrypted_request + * + * Description : Receives an encrypted request. + * + * Parameters : + * 1 : csp = Current client state (buffers, headers, etc...) + * + * Returns : JB_ERR_OK on success, + * JB_ERR_PARSE or JB_ERR_MEMORY otherwise + * + *********************************************************************/ +static jb_err receive_encrypted_request(struct client_state *csp) +{ + char buf[BUFFER_SIZE]; + int len; + char *p; + + do + { + log_error(LOG_LEVEL_HEADER, "Reading encrypted headers"); + if (!data_is_available(csp->cfd, (int)csp->config->keep_alive_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), + (unsigned char *)buf, sizeof(buf)); + if (len == -1) + { + return JB_ERR_PARSE; + } + if (add_to_iob(csp->client_iob, csp->config->buffer_limit, buf, len)) + { + return JB_ERR_MEMORY; + } + p = strstr(csp->client_iob->cur, "\r\n\r\n"); + } while (p == NULL); + + log_error(LOG_LEVEL_HEADER, "Encrypted headers received completely"); + + return JB_ERR_OK; +} + + +/********************************************************************* + * + * Function : process_encrypted_request + * + * Description : Receives and parses an encrypted request. + * + * Parameters : + * 1 : csp = Current client state (buffers, headers, etc...) + * + * Returns : JB_ERR_OK on success, + * JB_ERR_PARSE or JB_ERR_MEMORY otherwise + * + *********************************************************************/ +static jb_err process_encrypted_request(struct client_state *csp) +{ + char *p; + char *request_line; + jb_err err; + /* Temporary copy of the client's headers before they get enlisted in csp->https_headers */ + struct list header_list; + struct list *headers = &header_list; + + err = receive_encrypted_request(csp); + if (err != JB_ERR_OK) + { + /* XXX: Also used for JB_ERR_MEMORY */ + ssl_send_data(&(csp->mbedtls_client_attr.ssl), + (const unsigned char *)CHEADER, strlen(CHEADER)); + return err; + } + + /* We don't need get_request_line() because the whole HTTP head is buffered. */ + 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)); + 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)); + return JB_ERR_PARSE; + } + +#ifdef FEATURE_FORCE_LOAD + if (force_required(csp, request_line)) + { + csp->flags |= CSP_FLAG_FORCED; + } +#endif /* def FEATURE_FORCE_LOAD */ + + free_http_request(csp->http); + + err = parse_http_request(request_line, csp->http); + /* XXX: Restore ssl setting. This is ugly */ + csp->http->client_ssl = 1; + csp->http->server_ssl = 1; + + freez(request_line); + if (JB_ERR_OK != err) + { + ssl_send_data(&(csp->mbedtls_client_attr.ssl), + (const unsigned char *)CHEADER, strlen(CHEADER)); + /* XXX: Use correct size */ + log_error(LOG_LEVEL_CLF, "%s - - [%T] \"Invalid request\" 400 0", csp->ip_addr_str); + log_error(LOG_LEVEL_ERROR, + "Couldn't parse request line received from %s: %s", + csp->ip_addr_str, jb_err_to_string(err)); + + free_http_request(csp->http); + return JB_ERR_PARSE; + } + + /* Parse the rest of the client's headers. */ + init_list(headers); + for (;;) + { + p = get_header(csp->client_iob); + + if (p == NULL) + { + /* There are no additional headers to read. */ + break; + } + enlist(headers, p); + freez(p); + } + + if (JB_ERR_OK != get_destination_from_https_headers(headers, csp->http)) + { + /* + * Our attempts to get the request destination + * elsewhere failed. + */ + ssl_send_data(&(csp->mbedtls_client_attr.ssl), + (const unsigned char *)CHEADER, strlen(CHEADER)); + return JB_ERR_PARSE; + } + +#ifndef FEATURE_EXTENDED_HOST_PATTERNS + /* Split the domain we just got for pattern matching */ + init_domain_components(csp->http); +#endif + +#ifdef FEATURE_TOGGLE + if ((csp->flags & CSP_FLAG_TOGGLED_ON) != 0) +#endif + { + /* Determine the actions for this URL */ + get_url_actions(csp, csp->http); + } + + enlist(csp->https_headers, csp->http->cmd); + + /* Append the previously read headers */ + err = list_append_list_unique(csp->https_headers, headers); + destroy_list(headers); + if (JB_ERR_OK != err) + { + /* XXX: Send error message */ + return err; + } + + /* XXX: Work around crash */ + csp->error_message = NULL; + + /* XXX: Why do this here? */ + csp->http->ssl = 1; + + err = sed_https(csp); + if (JB_ERR_OK != err) + { + ssl_send_data(&(csp->mbedtls_client_attr.ssl), + (const unsigned char *)CHEADER, strlen(CHEADER)); + 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", + csp->ip_addr_str, csp->http->cmd); + return JB_ERR_PARSE; + } + + log_error(LOG_LEVEL_HEADER, "Encrypted request processed"); + log_applied_actions(csp->action); + + return err; + +} +#endif + + /********************************************************************* * * Function : handle_established_connection @@ -2026,7 +2387,7 @@ 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; @@ -2038,7 +2399,7 @@ static void handle_established_connection(struct client_state *csp) 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; @@ -2149,7 +2510,7 @@ static void handle_established_connection(struct client_state *csp) } #endif /* FEATURE_CONNECTION_KEEP_ALIVE */ -#ifdef FEATURE_HTTPS_FILTERING +#ifdef FEATURE_HTTPS_INSPECTION /* * Test if some data from client or destination server are pending * on TLS/SSL. We must work with them preferably. TLS/SSL data can @@ -2208,7 +2569,7 @@ static void handle_established_connection(struct client_state *csp) send_crunch_response(csp, error_response(csp, "connection-timeout")); } mark_server_socket_tainted(csp); -#ifdef FEATURE_HTTPS_FILTERING +#ifdef FEATURE_HTTPS_INSPECTION close_client_and_server_ssl_connections(csp); #endif return; @@ -2221,13 +2582,13 @@ static void handle_established_connection(struct client_state *csp) log_error(LOG_LEVEL_ERROR, "select() failed!: %E"); #endif mark_server_socket_tainted(csp); -#ifdef FEATURE_HTTPS_FILTERING +#ifdef FEATURE_HTTPS_INSPECTION close_client_and_server_ssl_connections(csp); #endif return; } } -#ifdef FEATURE_HTTPS_FILTERING +#ifdef FEATURE_HTTPS_INSPECTION else { /* set FD if some data are pending on TLS/SSL connections */ @@ -2327,7 +2688,7 @@ 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 +#ifdef FEATURE_HTTPS_INSPECTION /* * Reading data from standard or secured connection (HTTP/HTTPS) */ @@ -2359,7 +2720,7 @@ static void handle_established_connection(struct client_state *csp) } } else -#endif /* def FEATURE_HTTPS_FILTERING */ +#endif /* def FEATURE_HTTPS_INSPECTION */ { len = read_socket(csp->cfd, csp->receive_buffer, max_bytes_to_read); @@ -2392,7 +2753,7 @@ 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 +#ifdef FEATURE_HTTPS_INSPECTION close_client_and_server_ssl_connections(csp); #endif return; @@ -2429,7 +2790,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; @@ -2437,7 +2798,7 @@ 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) */ @@ -2458,7 +2819,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 ) @@ -2484,7 +2845,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; @@ -2553,7 +2914,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 )) @@ -2603,7 +2964,7 @@ 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) */ @@ -2625,7 +2986,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), @@ -2635,7 +2996,7 @@ static void handle_established_connection(struct client_state *csp) freez(hdr); freez(p); mark_server_socket_tainted(csp); -#ifdef FEATURE_HTTPS_FILTERING +#ifdef FEATURE_HTTPS_INSPECTION close_client_and_server_ssl_connections(csp); #endif return; @@ -2670,7 +3031,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 )) @@ -2701,14 +3062,14 @@ 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) */ @@ -2730,7 +3091,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) @@ -2741,7 +3102,7 @@ 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 +#ifdef FEATURE_HTTPS_INSPECTION close_client_and_server_ssl_connections(csp); #endif return; @@ -2761,7 +3122,7 @@ 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) */ @@ -2779,14 +3140,14 @@ 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 +#ifdef FEATURE_HTTPS_INSPECTION close_client_and_server_ssl_connections(csp); #endif return; @@ -2809,7 +3170,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; @@ -2829,7 +3190,7 @@ 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) */ @@ -2840,14 +3201,14 @@ static void handle_established_connection(struct client_state *csp) strlen(INVALID_SERVER_HEADERS_RESPONSE)); } 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; @@ -2895,7 +3256,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; @@ -2923,7 +3284,7 @@ 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) */ @@ -2934,14 +3295,14 @@ static void handle_established_connection(struct client_state *csp) strlen(INVALID_SERVER_HEADERS_RESPONSE)); } 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; @@ -2955,7 +3316,7 @@ 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) */ @@ -2973,7 +3334,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; @@ -3010,7 +3371,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; @@ -3027,7 +3388,7 @@ 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), @@ -3043,14 +3404,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)) @@ -3063,7 +3424,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; @@ -3088,7 +3449,7 @@ 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) */ @@ -3099,13 +3460,13 @@ static void handle_established_connection(struct client_state *csp) strlen(INVALID_SERVER_HEADERS_RESPONSE)); } 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; @@ -3114,12 +3475,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 +#ifdef FEATURE_HTTPS_INSPECTION close_client_and_server_ssl_connections(csp); #endif if (csp->content_length == 0) @@ -3179,7 +3540,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 @@ -3203,12 +3564,12 @@ static void chat(struct client_state *csp) return; } -#ifdef FEATURE_HTTPS_FILTERING +#ifdef FEATURE_HTTPS_INSPECTION /* * Setting flags to use old solution with SSL tunnel and to disable * certificates verification. */ - if (csp->http->ssl && !(csp->action->flags & ACTION_ENABLE_HTTPS_FILTER)) + if (csp->http->ssl && !(csp->action->flags & ACTION_HTTPS_INSPECTION)) { use_ssl_tunnel = 1; } @@ -3260,7 +3621,7 @@ static void chat(struct client_state *csp) * */ -#ifdef FEATURE_HTTPS_FILTERING +#ifdef FEATURE_HTTPS_INSPECTION /* * Presetting SSL client and server flags */ @@ -3286,7 +3647,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 @@ -3297,9 +3658,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. @@ -3353,7 +3721,60 @@ static void chat(struct client_state *csp) mark_connection_closed(&csp->server_connection); } #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ +#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. + */ + if (fwd->forward_host == NULL) + { + /* + * 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; + } + } + + 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? */ + 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; + } + /* + * We have an encrypted request. Check if one of the crunchers now + * wants it (for example because the previously invisible path was + * required to match). + */ + if (crunch_response_triggered(csp, crunchers_all)) + { + /* + * Yes. The client got the crunch response and we're done here. + */ + close_client_ssl_connection(csp); + return; + } + } +#endif /* * Connecting to destination server */ @@ -3399,7 +3820,7 @@ static void chat(struct client_state *csp) 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 @@ -3434,6 +3855,7 @@ static void chat(struct client_state *csp) log_error(LOG_LEVEL_CONNECT, "Sending request headers to: %s failed", http->hostport); mark_server_socket_tainted(csp); + close_client_ssl_connection(csp); return; } @@ -3452,6 +3874,7 @@ static void chat(struct client_state *csp) send_crunch_response(csp, rsp); } mark_server_socket_tainted(csp); + close_client_ssl_connection(csp); return; } @@ -3467,6 +3890,7 @@ static void chat(struct client_state *csp) write_socket(csp->cfd, server_response, (size_t)len); mark_server_socket_tainted(csp); + close_client_ssl_connection(csp); return; } @@ -3478,7 +3902,7 @@ static void chat(struct client_state *csp) /* * If TLS/SSL connection wasn't created and invalid certificate - * wasn't detected, we can interrupt this fuction. Otherwise, we + * wasn't detected, we can interrupt this function. Otherwise, we * must inform the client about invalid server certificate. */ if (ret != 0 @@ -3503,6 +3927,7 @@ static void chat(struct client_state *csp) log_error(LOG_LEVEL_ERROR, "Sending parent proxy response to client failed"); mark_server_socket_tainted(csp); + close_client_ssl_connection(csp); return; } }/* -END- if (fwd->forward_host != NULL) */ @@ -3513,25 +3938,38 @@ static void chat(struct client_state *csp) * 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 (ret != 0) { - rsp = error_response(csp, "connect-failed"); - if (rsp) + if (csp->server_cert_verification_result != SSL_CERT_VALID && + csp->server_cert_verification_result != SSL_CERT_NOT_VERIFIED) { - send_crunch_response(csp, rsp); + /* + * 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; + } + 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); + } + return; } - 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, @@ -3549,7 +3987,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 )) @@ -3570,7 +4008,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 { @@ -3585,36 +4023,9 @@ static void chat(struct client_state *csp) return; } } -#ifdef FEATURE_HTTPS_FILTERING +#ifdef FEATURE_HTTPS_INSPECTION else { - 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. - */ - - if (fwd->forward_host == NULL) - { - if (write_socket_delayed(csp->cfd, CSUCCEED, - strlen(CSUCCEED), get_write_delay(csp)) != 0) - { - log_error(LOG_LEVEL_ERROR, "Sending SUCCEED to client failed"); - close_client_and_server_ssl_connections(csp); - return; - } - } - - ret = create_client_ssl_connection(csp); - if (ret != 0) - { - log_error(LOG_LEVEL_ERROR, - "Can't open secure connection with client"); - close_client_and_server_ssl_connections(csp); - return; - } - /* * If server certificate is invalid, we must inform client and then * close connection with client. @@ -3625,8 +4036,18 @@ static void chat(struct client_state *csp) close_client_and_server_ssl_connections(csp); return; } + if (send_https_request(csp)) + { + rsp = error_response(csp, "connect-failed"); + if (rsp) + { + 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) */ @@ -4165,16 +4586,7 @@ 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(&certificate_mutex); privoxy_mutex_init(&rng_mutex); privoxy_mutex_init(&log_mutex); @@ -5212,7 +5624,7 @@ 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) {