* Rebuild the request line.
*/
freez(*request_line);
- *request_line = strdup(http->gpc);
- string_append(request_line, " ");
+#ifdef FEATURE_HTTPS_INSPECTION
+ if (fwd != NULL && fwd->forward_host &&
+ fwd->type != FORWARD_WEBSERVER && client_use_ssl(csp))
+ {
+ *request_line = strdup("CONNECT ");
+ }
+ else
+#endif
+ {
+ *request_line = strdup(http->gpc);
+ string_append(request_line, " ");
+ }
if (fwd != NULL && fwd->forward_host && fwd->type != FORWARD_WEBSERVER)
{
- string_append(request_line, http->url);
+#ifdef FEATURE_HTTPS_INSPECTION
+ if (client_use_ssl(csp))
+ {
+ char port_string[10];
+
+ string_append(request_line, http->host);
+ snprintf(port_string, sizeof(port_string), ":%d", http->port);
+ string_append(request_line, port_string);
+ }
+ else
+#endif
+ {
+ string_append(request_line, http->url);
+ }
}
else
{
if (to_read != 0)
{
- log_error(LOG_LEVEL_CONNECT, "Not enough request body has been read: expected %llu more bytes",
- csp->expected_client_content_length);
+ log_error(LOG_LEVEL_CONNECT,
+ "Not enough request body has been read: expected %lu more bytes",
+ to_read);
return 1;
}
- log_error(LOG_LEVEL_CONNECT, "The last %llu bytes of the request body have been read",
- csp->expected_client_content_length);
+ log_error(LOG_LEVEL_CONNECT,
+ "The last %d bytes of the request body have been read", len);
return 0;
}
/*********************************************************************
*
- * Function : receive_encrypted_request
+ * Function : receive_encrypted_request_headers
*
- * Description : Receives an encrypted request.
+ * Description : Receives the encrypted request headers when
+ * https-inspecting.
*
* Parameters :
* 1 : csp = Current client state (buffers, headers, etc...)
* JB_ERR_PARSE or JB_ERR_MEMORY otherwise
*
*********************************************************************/
-static jb_err receive_encrypted_request(struct client_state *csp)
+static jb_err receive_encrypted_request_headers(struct client_state *csp)
{
char buf[BUFFER_SIZE];
int len;
do
{
- log_error(LOG_LEVEL_HEADER, "Reading encrypted headers");
+ log_error(LOG_LEVEL_HEADER, "Waiting for encrypted client headers");
if (!is_ssl_pending(&(csp->ssl_client_attr)) &&
!data_is_available(csp->cfd, csp->config->socket_timeout))
{
/*********************************************************************
*
- * Function : process_encrypted_request
+ * Function : process_encrypted_request_headers
*
- * Description : Receives and parses an encrypted request.
+ * Description : Receives and parses the encrypted headers send
+ * by the client when https-inspecting.
*
* Parameters :
* 1 : csp = Current client state (buffers, headers, etc...)
* JB_ERR_PARSE or JB_ERR_MEMORY otherwise
*
*********************************************************************/
-static jb_err process_encrypted_request(struct client_state *csp)
+static jb_err process_encrypted_request_headers(struct client_state *csp)
{
char *p;
char *request_line;
csp->flags |= CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE;
}
#endif
- err = receive_encrypted_request(csp);
+ err = receive_encrypted_request_headers(csp);
if (err != JB_ERR_OK)
{
if (csp->client_iob->cur == NULL ||
return JB_ERR_PARSE;
}
- log_error(LOG_LEVEL_HEADER, "Encrypted request processed");
- log_applied_actions(csp->action);
+ log_error(LOG_LEVEL_HEADER, "Encrypted request headers processed");
log_error(LOG_LEVEL_REQUEST, "https://%s%s", csp->http->hostport,
csp->http->path);
{
const struct forward_spec *fwd;
- if (JB_ERR_OK != process_encrypted_request(csp))
+ if (JB_ERR_OK != process_encrypted_request_headers(csp))
{
csp->flags &= ~CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE;
return;
return;
}
+ log_applied_actions(csp->action);
+
log_error(LOG_LEVEL_CONNECT,
"Reusing server socket %d connected to %s. Requests already sent: %u.",
csp->server_connection.sfd, csp->server_connection.host,
* Function : handle_established_connection
*
* Description : Shuffle data between client and server once the
- * connection has been established.
+ * connection has been established and the request
+ * has been sent.
*
* Parameters :
* 1 : csp = Current client state (buffers, headers, etc...)
for (;;)
{
+#ifdef FEATURE_HTTPS_INSPECTION
+ if (server_use_ssl(csp) && is_ssl_pending(&(csp->ssl_server_attr)))
+ {
+ /*
+ * It's possible that the TLS library already consumed all the
+ * data the server intends to send. If that happens poll() and
+ * select() will no longer see the data as available so we have
+ * to skip the calls.
+ */
+ goto server_wants_to_talk;
+ }
+#endif
#ifndef HAVE_POLL
FD_ZERO(&rfds);
#ifdef FEATURE_CONNECTION_KEEP_ALIVE
n = select((int)maxfd + 1, &rfds, NULL, NULL, &timeout);
#endif /* def HAVE_POLL */
- /*server or client not responding in timeout */
+ /* Server or client not responding in timeout */
if (n == 0)
{
log_error(LOG_LEVEL_CONNECT, "Socket timeout %d reached: %s",
if (FD_ISSET(csp->server_connection.sfd, &rfds))
#endif /* HAVE_POLL */
{
+#ifdef FEATURE_HTTPS_INSPECTION
+ server_wants_to_talk:
+#endif
#ifdef FEATURE_CONNECTION_KEEP_ALIVE
/*
* If we are buffering content, we don't want to eat up to
}
/*
- * This is NOT the body, so
- * Let's pretend the server just sent us a blank line.
+ * This is not the body, so let's pretend the server just sent
+ * us a blank line.
*/
snprintf(csp->receive_buffer, csp->receive_buffer_size, "\r\n");
len = (int)strlen(csp->receive_buffer);
return;
}
- /* decide how to route the HTTP request */
- fwd = forward_url(csp, http);
-
#ifdef FEATURE_HTTPS_INSPECTION
/*
* Setting flags to use old solution with SSL tunnel and to disable
#endif
}
-
- freez(csp->headers->first->str);
- build_request_line(csp, fwd, &csp->headers->first->str);
-
/*
* We have a request. Check if one of the crunchers wants it
* unless the client wants to use TLS/SSL in which case we
return;
}
+#ifdef FEATURE_HTTPS_INSPECTION
+ if (client_use_ssl(csp) && !use_ssl_tunnel)
+ {
+ int ret;
+ /*
+ * 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 (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,
+ "Failed to open a secure connection with the client");
+ return;
+ }
+ if (JB_ERR_OK != process_encrypted_request_headers(csp))
+ {
+ 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.
+ */
+ return;
+ }
+ }
+#endif
+
log_applied_actions(csp->action);
+
+ /* decide how to route the HTTP request */
+ fwd = forward_url(csp, http);
+
+ freez(csp->headers->first->str);
+ build_request_line(csp, fwd, &csp->headers->first->str);
+
if (fwd->forward_host)
{
log_error(LOG_LEVEL_CONNECT, "via [%s]:%d to: %s",
mark_connection_closed(&csp->server_connection);
}
#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
-#ifdef FEATURE_HTTPS_INSPECTION
- if (client_use_ssl(csp) && !use_ssl_tunnel)
- {
- int ret;
- /*
- * 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 (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,
- "Failed to open a secure connection with the client");
- return;
- }
- if (JB_ERR_OK != process_encrypted_request(csp))
- {
- 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.
- */
- return;
- }
- }
-#endif
/*
* Connecting to destination server
*/
"can't bind to %s:%d: There may be another Privoxy "
"or some other proxy running on port %d",
bind_address, hport, hport);
+ exit(-1);
case -2:
log_error(LOG_LEVEL_FATAL,
"can't bind to %s:%d: The hostname is not resolvable",
bind_address, hport);
+ exit(-1);
default:
log_error(LOG_LEVEL_FATAL, "can't bind to %s:%d: %E",
bind_address, hport);
+ exit(-1);
}
/* shouldn't get here */
if ((0 != config->max_client_connections)
&& (active_threads >= config->max_client_connections))
{
- log_error(LOG_LEVEL_CONNECT,
+ log_error(LOG_LEVEL_ERROR,
"Rejecting connection from %s. Maximum number of connections reached.",
csp->ip_addr_str);
write_socket_delayed(csp->cfd, TOO_MANY_CONNECTIONS_RESPONSE,
}
#endif
-#if defined(_WIN32) && !defined(_CYGWIN) && !defined(SELECTED_ONE_OPTION)
+#if defined(_WIN32) && !defined(SELECTED_ONE_OPTION)
#define SELECTED_ONE_OPTION
child_id = _beginthread(
(void (*)(void *))serve,
log_error(LOG_LEVEL_INFO, "Graceful termination requested.");
+ close_ports_helper(bfds);
+
unload_current_config_file();
unload_current_actions_file();
unload_current_re_filterfile();