* 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
#include "project.h"
#include "list.h"
#include "jcc.h"
-#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_HTTPS_INSPECTION
#include "ssl.h"
#endif
#include "filters.h"
privoxy_mutex_t connection_reuse_mutex;
#ifdef LIMIT_MUTEX_NUMBER
- privoxy_mutex_t certificates_mutexes[32];
+privoxy_mutex_t certificates_mutexes[32];
#else
- privoxy_mutex_t certificates_mutexes[65536];
+privoxy_mutex_t certificates_mutexes[65536];
#endif /* LIMIT_MUTEX_NUMBER */
- privoxy_mutex_t rng_mutex;
+privoxy_mutex_t rng_mutex;
#ifdef FEATURE_EXTERNAL_FILTERS
privoxy_mutex_t external_filter_mutex;
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),
}
-#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 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
"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
init_domain_components(csp->http);
#endif
- /*
- * Determine the actions for this URL
- */
#ifdef FEATURE_TOGGLE
- if (!(csp->flags & CSP_FLAG_TOGGLED_ON))
- {
- /* Most compatible set of actions (i.e. none) */
- init_current_action(csp->action);
- }
- else
-#endif /* ndef FEATURE_TOGGLE */
+ if ((csp->flags & CSP_FLAG_TOGGLED_ON) != 0)
+#endif
{
+ /* Determine the actions for this URL */
get_url_actions(csp, csp->http);
}
}
log_error(LOG_LEVEL_HEADER, "Encrypted request processed");
+ log_applied_actions(csp->action);
return err;
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;
}
#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
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;
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 */
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)
*/
}
}
else
-#endif /* def FEATURE_HTTPS_FILTERING */
+#endif /* def FEATURE_HTTPS_INSPECTION */
{
len = read_socket(csp->cfd, csp->receive_buffer, max_bytes_to_read);
{
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;
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;
}
#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
-#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_HTTPS_INSPECTION
/*
* Reading data from standard or secured connection (HTTP/HTTPS)
*/
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
)
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;
{
if (server_body || (http->ssl
-#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_HTTPS_INSPECTION
&& use_ssl_tunnel
#endif
))
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)
*/
}
}
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),
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;
* content-filtering.
*/
if (server_body || (http->ssl
-#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_HTTPS_INSPECTION
&& use_ssl_tunnel
#endif
))
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)
*/
}
}
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)
"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;
}
else
{
-#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_HTTPS_INSPECTION
/*
* Sending data with standard or secured connection (HTTP/HTTPS)
*/
}
}
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;
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;
"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)
*/
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;
}
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;
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)
*/
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;
{
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)
*/
}
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;
*/
freez(hdr);
mark_server_socket_tainted(csp);
-#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_HTTPS_INSPECTION
close_client_and_server_ssl_connections(csp);
#endif
return;
* 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),
*/
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))
*/
freez(hdr);
mark_server_socket_tainted(csp);
-#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_HTTPS_INSPECTION
close_client_and_server_ssl_connections(csp);
#endif
return;
"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)
*/
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;
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)
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
return;
}
-#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_HTTPS_INSPECTION
/*
* Setting flags to use old solution with SSL tunnel and to disable
* certificates verification.
*
*/
-#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_HTTPS_INSPECTION
/*
* Presetting SSL client and server flags
*/
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
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.
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;
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
/*
* 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
* 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,
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
))
* 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
{
return;
}
}
-#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_HTTPS_INSPECTION
else
{
/*
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) */
/* 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)
{