Add config option socket-timeout to control the time
authorFabian Keil <fk@fabiankeil.de>
Sat, 20 Dec 2008 14:53:55 +0000 (14:53 +0000)
committerFabian Keil <fk@fabiankeil.de>
Sat, 20 Dec 2008 14:53:55 +0000 (14:53 +0000)
Privoxy waits for data to arrive on a socket. Useful
in case of stale ssh tunnels or when fuzz-testing.

jbsockets.c
jbsockets.h
jcc.c
loadcfg.c
project.h

index 0693fe4..f7443ec 100644 (file)
@@ -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 $
 /*********************************************************************
  *
  * 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 $
  *
  * 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.
  *    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
 /*********************************************************************
  *
  * Function    :  close_socket
index 72bfc69..8a58066 100644 (file)
@@ -1,6 +1,6 @@
 #ifndef JBSOCKETS_H_INCLUDED
 #define JBSOCKETS_H_INCLUDED
 #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 $
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/jbsockets.h,v $
  *
  * Revisions   :
  *    $Log: jbsockets.h,v $
  *
  * 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)
  *    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 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);
 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 eebac43..59086d5 100644 (file)
--- 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 $
 /*********************************************************************
  *
  * 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 $
  *
  * 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.
  *
  *    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
    {
 
    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;
       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.
           */
           * 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)
          {
          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;
 
    /* Skeleton for HTTP response, if we should intercept the request */
    struct http_response *rsp;
+   struct timeval timeout;
 
    memset(buf, 0, sizeof(buf));
 
    memset(buf, 0, sizeof(buf));
+   memset(&timeout, 0, sizeof(timeout));
+   timeout.tv_sec = csp->config->socket_timeout;
 
    http = csp->http;
 
 
    http = csp->http;
 
@@ -2716,9 +2737,15 @@ static void chat(struct client_state *csp)
       }
 #endif  /* FEATURE_CONNECTION_KEEP_ALIVE */
 
       }
 #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);
       {
          log_error(LOG_LEVEL_ERROR, "select() failed!: %E");
          mark_server_socket_tainted(csp);
index 1560697..2b6e95c 100644 (file)
--- 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 $
 /*********************************************************************
  *
  * 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 $
  *
  * 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.
  *
  *    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_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" */
 #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->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;
    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;
 
             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
  * *************************************************************************/
 /* *************************************************************************
  * split-large-cgi-forms
  * *************************************************************************/
index 7aee884..ad3f80d 100644 (file)
--- a/project.h
+++ b/project.h
@@ -1,7 +1,7 @@
 #ifndef PROJECT_H_INCLUDED
 #define PROJECT_H_INCLUDED
 /** Version string. */
 #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 $
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/project.h,v $
@@ -37,6 +37,9 @@
  *
  * Revisions   :
  *    $Log: project.h,v $
  *
  * 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.
  *
  *    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;
 
    /** 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;
 
    /** All options from the config file, HTML-formatted. */
    char *proxy_args;