From d05721eca2f3d5cea3b36b88a5abed179013e59c Mon Sep 17 00:00:00 2001 From: Fabian Keil Date: Sat, 20 Dec 2008 14:53:55 +0000 Subject: [PATCH] Add config option socket-timeout to control the time Privoxy waits for data to arrive on a socket. Useful in case of stale ssh tunnels or when fuzz-testing. --- jbsockets.c | 45 ++++++++++++++++++++++++++++++++++++++++++++- jbsockets.h | 8 +++++++- jcc.c | 33 ++++++++++++++++++++++++++++++--- loadcfg.c | 28 +++++++++++++++++++++++++++- project.h | 8 +++++++- 5 files changed, 115 insertions(+), 7 deletions(-) diff --git a/jbsockets.c b/jbsockets.c index 0693fe49..f7443ec9 100644 --- a/jbsockets.c +++ b/jbsockets.c @@ -1,4 +1,4 @@ -const char jbsockets_rcs[] = "$Id: jbsockets.c,v 1.48 2008/09/04 08:13:58 fabiankeil Exp $"; +const char jbsockets_rcs[] = "$Id: jbsockets.c,v 1.49 2008/11/10 17:03:57 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/jbsockets.c,v $ @@ -35,6 +35,9 @@ const char jbsockets_rcs[] = "$Id: jbsockets.c,v 1.48 2008/09/04 08:13:58 fabian * * Revisions : * $Log: jbsockets.c,v $ + * Revision 1.49 2008/11/10 17:03:57 fabiankeil + * Fix a gcc44 warning and remove a now-obsolete cast. + * * Revision 1.48 2008/09/04 08:13:58 fabiankeil * Prepare for critical sections on Windows by adding a * layer of indirection before the pthread mutex functions. @@ -583,6 +586,46 @@ int read_socket(jb_socket fd, char *buf, int len) } +/********************************************************************* + * + * Function : data_is_available + * + * Description : Waits for data to arrive on a socket. + * + * Parameters : + * 1 : fd = file descriptor of the socket to read + * 2 : seconds_to_wait = number of seconds after which we give up. + * + * Returns : TRUE if data arrived in time, + * FALSE otherwise. + * + *********************************************************************/ +int data_is_available(jb_socket fd, int seconds_to_wait) +{ + fd_set rfds; + struct timeval timeout; + int n; + + memset(&timeout, 0, sizeof(timeout)); + timeout.tv_sec = seconds_to_wait; + +#ifdef __OS2__ + /* Copy and pasted from jcc.c ... */ + memset(&rfds, 0, sizeof(fd_set)); +#else + FD_ZERO(&rfds); +#endif + FD_SET(fd, &rfds); + + n = select(fd+1, &rfds, NULL, NULL, &timeout); + + /* + * XXX: Do we care about the different error conditions? + */ + return (n == 1); +} + + /********************************************************************* * * Function : close_socket diff --git a/jbsockets.h b/jbsockets.h index 72bfc69e..8a58066a 100644 --- a/jbsockets.h +++ b/jbsockets.h @@ -1,6 +1,6 @@ #ifndef JBSOCKETS_H_INCLUDED #define JBSOCKETS_H_INCLUDED -#define JBSOCKETS_H_VERSION "$Id: jbsockets.h,v 1.12 2006/07/18 14:48:46 david__schmidt Exp $" +#define JBSOCKETS_H_VERSION "$Id: jbsockets.h,v 1.13 2008/03/21 11:13:59 fabiankeil Exp $" /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/jbsockets.h,v $ @@ -37,6 +37,11 @@ * * Revisions : * $Log: jbsockets.h,v $ + * Revision 1.13 2008/03/21 11:13:59 fabiankeil + * Only gather host information if it's actually needed. + * Also move the code out of accept_connection() so it's less likely + * to delay other incoming connections if the host is misconfigured. + * * Revision 1.12 2006/07/18 14:48:46 david__schmidt * Reorganizing the repository: swapping out what was HEAD (the old 3.1 branch) * with what was really the latest development (the v_3_0_branch branch) @@ -113,6 +118,7 @@ extern int write_socket(jb_socket fd, const char *buf, ssize_t n); extern int write_socket(jb_socket fd, const char *buf, size_t n); #endif extern int read_socket(jb_socket fd, char *buf, int n); +extern int data_is_available(jb_socket fd, int seconds_to_wait); extern void close_socket(jb_socket fd); extern int bind_port(const char *hostnam, int portnum, jb_socket *pfd); diff --git a/jcc.c b/jcc.c index eebac438..59086d55 100644 --- a/jcc.c +++ b/jcc.c @@ -1,4 +1,4 @@ -const char jcc_rcs[] = "$Id: jcc.c,v 1.212 2008/12/14 15:46:22 fabiankeil Exp $"; +const char jcc_rcs[] = "$Id: jcc.c,v 1.213 2008/12/15 18:45:51 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/jcc.c,v $ @@ -33,6 +33,10 @@ const char jcc_rcs[] = "$Id: jcc.c,v 1.212 2008/12/14 15:46:22 fabiankeil Exp $" * * Revisions : * $Log: jcc.c,v $ + * Revision 1.213 2008/12/15 18:45:51 fabiankeil + * When logging crunches, log the whole URL, so one can easily + * differentiate between vanilla HTTP and CONNECT requests. + * * Revision 1.212 2008/12/14 15:46:22 fabiankeil * Give crunched requests their own log level. * @@ -2161,6 +2165,13 @@ static char *get_request_line(struct client_state *csp) do { + if (!data_is_available(csp->cfd, csp->config->socket_timeout)) + { + log_error(LOG_LEVEL_ERROR, + "Stopped waiting for the request line."); + return '\0'; + } + len = read_socket(csp->cfd, buf, sizeof(buf) - 1); if (len <= 0) return NULL; @@ -2293,6 +2304,13 @@ static jb_err receive_client_request(struct client_state *csp) * We didn't receive a complete header * line yet, get the rest of it. */ + if (!data_is_available(csp->cfd, csp->config->socket_timeout)) + { + log_error(LOG_LEVEL_ERROR, + "Stopped grabbing the client headers."); + return JB_ERR_PARSE; + } + len = read_socket(csp->cfd, buf, sizeof(buf) - 1); if (len <= 0) { @@ -2474,8 +2492,11 @@ static void chat(struct client_state *csp) /* Skeleton for HTTP response, if we should intercept the request */ struct http_response *rsp; + struct timeval timeout; memset(buf, 0, sizeof(buf)); + memset(&timeout, 0, sizeof(timeout)); + timeout.tv_sec = csp->config->socket_timeout; http = csp->http; @@ -2716,9 +2737,15 @@ static void chat(struct client_state *csp) } #endif /* FEATURE_CONNECTION_KEEP_ALIVE */ - n = select((int)maxfd+1, &rfds, NULL, NULL, NULL); + n = select((int)maxfd+1, &rfds, NULL, NULL, &timeout); - if (n < 0) + if (n == 0) + { + log_error(LOG_LEVEL_ERROR, "Didn't receive data in time."); + mark_server_socket_tainted(csp); + return; + } + else if (n < 0) { log_error(LOG_LEVEL_ERROR, "select() failed!: %E"); mark_server_socket_tainted(csp); diff --git a/loadcfg.c b/loadcfg.c index 1560697a..2b6e95c7 100644 --- a/loadcfg.c +++ b/loadcfg.c @@ -1,4 +1,4 @@ -const char loadcfg_rcs[] = "$Id: loadcfg.c,v 1.81 2008/11/13 09:08:42 fabiankeil Exp $"; +const char loadcfg_rcs[] = "$Id: loadcfg.c,v 1.82 2008/11/16 12:43:49 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/loadcfg.c,v $ @@ -35,6 +35,11 @@ const char loadcfg_rcs[] = "$Id: loadcfg.c,v 1.81 2008/11/13 09:08:42 fabiankeil * * Revisions : * $Log: loadcfg.c,v $ + * Revision 1.82 2008/11/16 12:43:49 fabiankeil + * Turn keep-alive support into a runtime feature + * that is disabled by setting keep-alive-timeout + * to a negative value. + * * Revision 1.81 2008/11/13 09:08:42 fabiankeil * Add new config option: keep-alive-timeout. * @@ -582,6 +587,7 @@ static struct file_list *current_configfile = NULL; #define hash_permit_access 3587953268ul /* "permit-access" */ #define hash_proxy_info_url 3903079059ul /* "proxy-info-url" */ #define hash_single_threaded 4250084780ul /* "single-threaded" */ +#define hash_socket_timeout 1809001761ul /* "socket-timeout" */ #define hash_split_large_cgi_forms 671658948ul /* "split-large-cgi-forms" */ #define hash_suppress_blocklists 1948693308ul /* "suppress-blocklists" */ #define hash_templdir 11067889ul /* "templdir" */ @@ -783,6 +789,7 @@ struct configuration_spec * load_config(void) config->usermanual = strdup(USER_MANUAL_URL); config->proxy_args = strdup(""); config->forwarded_connect_retries = 0; + config->socket_timeout = 180; config->feature_flags &= ~RUNTIME_FEATURE_CGI_TOGGLE; config->feature_flags &= ~RUNTIME_FEATURE_SPLIT_LARGE_FORMS; config->feature_flags &= ~RUNTIME_FEATURE_ACCEPT_INTERCEPTED_REQUESTS; @@ -1482,6 +1489,25 @@ struct configuration_spec * load_config(void) config->multi_threaded = 0; continue; +/* ************************************************************************* + * socket-timeout numer_of_seconds + * *************************************************************************/ + case hash_socket_timeout : + if (*arg != '\0') + { + int socket_timeout = atoi(arg); + if (0 < socket_timeout) + { + config->socket_timeout = socket_timeout; + } + else + { + log_error(LOG_LEVEL_FATAL, + "Invalid socket-timeout: '%s'", arg); + } + } + continue; + /* ************************************************************************* * split-large-cgi-forms * *************************************************************************/ diff --git a/project.h b/project.h index 7aee884a..ad3f80d4 100644 --- a/project.h +++ b/project.h @@ -1,7 +1,7 @@ #ifndef PROJECT_H_INCLUDED #define PROJECT_H_INCLUDED /** Version string. */ -#define PROJECT_H_VERSION "$Id: project.h,v 1.125 2008/11/20 08:22:28 fabiankeil Exp $" +#define PROJECT_H_VERSION "$Id: project.h,v 1.126 2008/12/14 17:02:54 fabiankeil Exp $" /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/project.h,v $ @@ -37,6 +37,9 @@ * * Revisions : * $Log: project.h,v $ + * Revision 1.126 2008/12/14 17:02:54 fabiankeil + * Fix a cparser warning. + * * Revision 1.125 2008/11/20 08:22:28 fabiankeil * Remove an obsolete comment. * @@ -1788,6 +1791,9 @@ struct configuration_spec /** Number of retries in case a forwarded connection attempt fails */ int forwarded_connect_retries; + /* Timeout when waiting on sockets for data to become available. */ + int socket_timeout; + /** All options from the config file, HTML-formatted. */ char *proxy_args; -- 2.39.2