Remove the treat-forbidden-connects-like-blocks action. We now
[privoxy.git] / jcc.c
diff --git a/jcc.c b/jcc.c
index e5eb7f5..82ab453 100644 (file)
--- a/jcc.c
+++ b/jcc.c
@@ -1,4 +1,4 @@
-const char jcc_rcs[] = "$Id: jcc.c,v 1.151 2007/09/29 10:21:16 fabiankeil Exp $";
+const char jcc_rcs[] = "$Id: jcc.c,v 1.168 2008/03/02 12:25:25 fabiankeil Exp $";
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/jcc.c,v $
@@ -33,6 +33,75 @@ const char jcc_rcs[] = "$Id: jcc.c,v 1.151 2007/09/29 10:21:16 fabiankeil Exp $"
  *
  * Revisions   :
  *    $Log: jcc.c,v $
+ *    Revision 1.168  2008/03/02 12:25:25  fabiankeil
+ *    Also use shiny new connect_port_is_forbidden() in jcc.c.
+ *
+ *    Revision 1.167  2008/02/23 16:57:12  fabiankeil
+ *    Rename url_actions() to get_url_actions() and let it
+ *    use the standard parameter ordering.
+ *
+ *    Revision 1.166  2008/02/23 16:33:43  fabiankeil
+ *    Let forward_url() use the standard parameter ordering
+ *    and mark its second parameter immutable.
+ *
+ *    Revision 1.165  2008/02/02 19:36:56  fabiankeil
+ *    Remove the "Listening ... for local connections only" log message.
+ *    Whether or not remote connections are able to reach Privoxy is up
+ *    to the operating system.
+ *
+ *    Revision 1.164  2007/12/16 18:32:46  fabiankeil
+ *    Prevent the log messages for CONNECT requests to unacceptable
+ *    ports from printing the limit-connect argument as [null] if
+ *    limit-connect hasn't been explicitly enabled.
+ *
+ *    Revision 1.163  2007/12/13 01:47:11  david__schmidt
+ *    Make sure all console-mode apps get a usage() instance
+ *
+ *    Revision 1.162  2007/12/06 17:54:57  fabiankeil
+ *    Reword NO_SERVER_DATA_RESPONSE to make it harder
+ *    to misunderstand what the message is all about.
+ *
+ *    Revision 1.161  2007/12/04 19:44:22  fabiankeil
+ *    Unbreak trustfile which previously didn't work without
+ *    FEATURE_TOGGLE. Fixes BR#1843585, reported by Lee.
+ *
+ *    Revision 1.160  2007/11/29 18:00:29  fabiankeil
+ *    Plug memory leak. Spotted by Valgrind, triggered by
+ *    Privoxy-Regression-Test feeding proxyfuzz.py.
+ *
+ *    Revision 1.159  2007/11/24 14:34:09  fabiankeil
+ *    In the HTTP snipplets, refer to the client as client.
+ *
+ *    Revision 1.158  2007/11/11 16:44:17  fabiankeil
+ *    Emit a log message when activating the MS IIS5 hack.
+ *
+ *    Revision 1.157  2007/11/03 17:34:49  fabiankeil
+ *    Log the "weak randomization factor" warning only
+ *    once for mingw32 and provide some more details.
+ *
+ *    Revision 1.156  2007/11/01 18:20:58  fabiankeil
+ *    Initialize log module after initializing mutexes, future
+ *    deadlocks in that code should now work cross-platform.
+ *
+ *    Revision 1.155  2007/10/23 20:12:45  fabiankeil
+ *    Fix first CSUCCEED line to end in \r\n as required by RFC1945.
+ *    Reported by Bert van Leeuwen in BR#1818808.
+ *
+ *    Revision 1.154  2007/10/19 17:00:08  fabiankeil
+ *    Downgrade "Flushing header and buffers" message to LOG_LEVEL_INFO.
+ *
+ *    Revision 1.153  2007/10/14 14:12:41  fabiankeil
+ *    When in daemon mode, close stderr after the configuration file has been
+ *    parsed the first time. If logfile isn't set, stop logging. Fixes BR#897436.
+ *
+ *    Revision 1.152  2007/10/04 18:03:34  fabiankeil
+ *    - Fix a crash when parsing invalid requests whose first header
+ *      is rejected by get_header(). Regression (re?)introduced
+ *      in r1.143 by yours truly.
+ *    - Move ACTION_VANILLA_WAFER handling into parsers.c's
+ *      client_cookie_adder() to make sure send-vanilla-wafer can be
+ *      controlled through tags (and thus regression-tested).
+ *
  *    Revision 1.151  2007/09/29 10:21:16  fabiankeil
  *    - Move get_filter_function() from jcc.c to filters.c
  *      so the filter functions can be static.
@@ -1012,7 +1081,7 @@ static void build_request_line(struct client_state *csp, const struct forward_sp
 static jb_err change_request_destination(struct client_state *csp);
 static void chat(struct client_state *csp);
 static void serve(struct client_state *csp);
-#if defined(unix)
+#if !defined(_WIN32) || defined(_WIN_CONSOLE)
 static void usage(const char *myname);
 #endif
 static void initialize_mutexes(void);
@@ -1067,37 +1136,31 @@ int received_hup_signal = 0;
 
 /* HTTP snipplets. */
 static const char CSUCCEED[] =
-   "HTTP/1.0 200 Connection established\n"
+   "HTTP/1.0 200 Connection established\r\n"
    "Proxy-Agent: Privoxy/" VERSION "\r\n\r\n";
 
 static const char CHEADER[] =
-   "HTTP/1.0 400 Invalid header received from browser\r\n"
+   "HTTP/1.0 400 Invalid header received from client\r\n"
    "Proxy-Agent: Privoxy " VERSION "\r\n"
    "Content-Type: text/plain\r\n"
    "Connection: close\r\n\r\n"
-   "Invalid header received from browser.\r\n";
-
-static const char CFORBIDDEN[] =
-   "HTTP/1.0 403 Connection not allowable\r\n"
-   "Proxy-Agent: Privoxy " VERSION "\r\n"
-   "X-Hint: If you read this message interactively, then you know why this happens ,-)\r\n"
-   "Connection: close\r\n\r\n";
+   "Invalid header received from client.\r\n";
 
 static const char FTP_RESPONSE[] =
-   "HTTP/1.0 400 Invalid request received from browser\r\n"
+   "HTTP/1.0 400 Invalid request received from client\r\n"
    "Content-Type: text/plain\r\n"
    "Connection: close\r\n\r\n"
    "Invalid request. Privoxy doesn't support FTP.\r\n";
 
 static const char GOPHER_RESPONSE[] =
-   "HTTP/1.0 400 Invalid request received from browser\r\n"
+   "HTTP/1.0 400 Invalid request received from client\r\n"
    "Content-Type: text/plain\r\n"
    "Connection: close\r\n\r\n"
    "Invalid request. Privoxy doesn't support gopher.\r\n";
 
 /* XXX: should be a template */
 static const char MISSING_DESTINATION_RESPONSE[] =
-   "HTTP/1.0 400 Bad request received from browser\r\n"
+   "HTTP/1.0 400 Bad request received from client\r\n"
    "Proxy-Agent: Privoxy " VERSION "\r\n"
    "Content-Type: text/plain\r\n"
    "Connection: close\r\n\r\n"
@@ -1110,12 +1173,12 @@ static const char NO_SERVER_DATA_RESPONSE[] =
    "Content-Type: text/plain\r\n"
    "Connection: close\r\n\r\n"
    "Empty server or forwarder response.\r\n"
-   "The connection was closed without sending any data.\r\n";
+   "The connection has been closed but Privoxy didn't receive any data.\r\n";
 
 #if 0
 /* XXX: should be a template */
 static const char NULL_BYTE_RESPONSE[] =
-   "HTTP/1.0 400 Bad request received from browser\r\n"
+   "HTTP/1.0 400 Bad request received from client\r\n"
    "Proxy-Agent: Privoxy " VERSION "\r\n"
    "Content-Type: text/plain\r\n"
    "Connection: close\r\n\r\n"
@@ -1981,6 +2044,7 @@ static void chat(struct client_state *csp)
          if (len <= 0)
          {
             log_error(LOG_LEVEL_ERROR, "read from client failed: %E");
+            destroy_list(headers);
             return;
          }
          
@@ -1990,6 +2054,7 @@ static void chat(struct client_state *csp)
           */
          if (add_to_iob(csp, buf, len))
          {
+            destroy_list(headers);
             return;
          }
          continue;
@@ -2019,7 +2084,7 @@ static void chat(struct client_state *csp)
           * An error response has already been send
           * and we're done here.
           */
-          return;
+         return;
       }
    }
 
@@ -2035,7 +2100,7 @@ static void chat(struct client_state *csp)
    else
 #endif /* ndef FEATURE_TOGGLE */
    {
-      url_actions(http, csp);
+      get_url_actions(csp, http);
    }
 
    /* 
@@ -2080,7 +2145,8 @@ static void chat(struct client_state *csp)
    }
 
    /* decide how to route the HTTP request */
-   if (NULL == (fwd = forward_url(http, csp)))
+   fwd = forward_url(csp, http);
+   if (NULL == fwd)
    {
       log_error(LOG_LEVEL_FATAL, "gateway spec is NULL!?!?  This can't happen!");
       /* Never get here - LOG_LEVEL_FATAL causes program exit */
@@ -2123,50 +2189,17 @@ static void chat(struct client_state *csp)
     *
     */
 
-   /*
-    * Check if a CONNECT request is allowable:
-    * In the absence of a +limit-connect action, allow only port 443.
-    * If there is an action, allow whatever matches the specificaton.
-    */
-   if(http->ssl)
+   if (http->ssl && connect_port_is_forbidden(csp))
    {
-      if(  ( !(csp->action->flags & ACTION_LIMIT_CONNECT) && csp->http->port != 443)
-           || (csp->action->flags & ACTION_LIMIT_CONNECT
-              && !match_portlist(csp->action->string[ACTION_STRING_LIMIT_CONNECT], csp->http->port)) )
-      {
-         if (csp->action->flags & ACTION_TREAT_FORBIDDEN_CONNECTS_LIKE_BLOCKS)
-         {
-            /*
-             * The response may confuse some clients,
-             * but makes unblocking easier.
-             *
-             * XXX: It seems to work with all major browsers,
-             * so we should consider returning a body by default someday ... 
-             */
-            log_error(LOG_LEVEL_INFO, "Request from %s marked for blocking. "
-               "limit-connect{%s} doesn't allow CONNECT requests to port %d.",
-               csp->ip_addr_str, csp->action->string[ACTION_STRING_LIMIT_CONNECT],
-               csp->http->port);
-            csp->action->flags |= ACTION_BLOCK;
-            http->ssl = 0;
-         }
-         else
-         {
-            write_socket(csp->cfd, CFORBIDDEN, strlen(CFORBIDDEN));
-            log_error(LOG_LEVEL_INFO, "Request from %s denied. "
-               "limit-connect{%s} doesn't allow CONNECT requests to port %d.",
-               csp->ip_addr_str, csp->action->string[ACTION_STRING_LIMIT_CONNECT],
-               csp->http->port);
-            assert(NULL != csp->http->ocmd);
-            log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 403 0", csp->ip_addr_str, csp->http->ocmd);
-
-            list_remove_all(csp->headers);
-            /*
-             * XXX: For consistency we might want to log a crunch message here.
-             */
-            return;
-         }
-      }
+      const char *acceptable_connect_ports =
+         csp->action->string[ACTION_STRING_LIMIT_CONNECT] ?
+         csp->action->string[ACTION_STRING_LIMIT_CONNECT] :
+         "443 (implied default)";
+      log_error(LOG_LEVEL_INFO, "Request from %s marked for blocking. "
+         "limit-connect{%s} doesn't allow CONNECT requests to port %d.",
+         csp->ip_addr_str, acceptable_connect_ports, csp->http->port);
+      csp->action->flags |= ACTION_BLOCK;
+      http->ssl = 0;
    }
 
    if (http->ssl == 0)
@@ -2494,6 +2527,9 @@ static void chat(struct client_state *csp)
              * This is NOT the body, so
              * Let's pretend the server just sent us a blank line.
              */
+            log_error(LOG_LEVEL_INFO,
+               "Malformerd HTTP headers detected and MS IIS5 hack enabled. "
+               "Expect an invalid response or even no response at all.");
             snprintf(buf, sizeof(buf), "\r\n");
             len = (int)strlen(buf);
 
@@ -2525,7 +2561,7 @@ static void chat(struct client_state *csp)
                   size_t hdrlen;
                   int flushed;
 
-                  log_error(LOG_LEVEL_ERROR, "Flushing header and buffers. Stepping back from filtering.");
+                  log_error(LOG_LEVEL_INFO, "Flushing header and buffers. Stepping back from filtering.");
 
                   hdr = list_to_text(csp->headers);
                   if (hdr == NULL)
@@ -2790,7 +2826,7 @@ static int32 server_thread(void *data)
 #endif
 
 
-#if defined(unix)
+#if !defined(_WIN32) || defined(_WIN_CONSOLE)
 /*********************************************************************
  *
  * Function    :  usage
@@ -2819,7 +2855,7 @@ static void usage(const char *myname)
    exit(2);
 
 }
-#endif /* defined(unix) */
+#endif /* #if !defined(_WIN32) || defined(_WIN_CONSOLE) */
 
 
 /*********************************************************************
@@ -3084,6 +3120,7 @@ int main(int argc, const char *argv[])
    files->next = NULL;
    clients->next = NULL;
 
+   /* XXX: factor out initialising after the next stable release. */
 #ifdef AMIGA
    InitAmiga();
 #elif defined(_WIN32)
@@ -3093,9 +3130,21 @@ int main(int argc, const char *argv[])
    /* Prepare mutexes if supported and necessary. */
    initialize_mutexes();
 
+   /* Enable logging until further notice. */
+   init_log_module(Argv[0]);
+
    random_seed = (unsigned int)time(NULL);
 #ifdef HAVE_RANDOM
    srandom(random_seed);
+#elif defined (_WIN32)
+   /*
+    * See pick_from_range() in miscutil.c for details.
+    */
+   log_error(LOG_LEVEL_INFO,
+      "No thread-safe PRNG implemented for your platform. "
+      "Using weak \'randomization\' factor which will "
+      "limit the already questionable usefulness of "
+      "header-time-randomizing actions (disabled by default).");
 #else
    srand(random_seed);
 #endif /* ifdef HAVE_RANDOM */
@@ -3203,10 +3252,9 @@ int main(int argc, const char *argv[])
          close ( fd );
       }
 #endif /* 1 */
-      /* FIXME: should close stderr (fd 2) here too, but the test
-       * for existence
-       * and load config file is done in listen_loop() and puts
-       * some messages on stderr there.
+      /*
+       * stderr (fd 2) will be closed later on, when the
+       * log file has been parsed.
        */
 
       close( 0 );
@@ -3336,16 +3384,7 @@ static jb_socket bind_port_helper(struct configuration_spec * config)
    int result;
    jb_socket bfd;
 
-   if ( (config->haddr != NULL)
-     && (config->haddr[0] == '1')
-     && (config->haddr[1] == '2')
-     && (config->haddr[2] == '7')
-     && (config->haddr[3] == '.') )
-   {
-      log_error(LOG_LEVEL_INFO, "Listening on port %d for local connections only",
-                config->hport);
-   }
-   else if (config->haddr == NULL)
+   if (config->haddr == NULL)
    {
       log_error(LOG_LEVEL_INFO, "Listening on port %d on all IP addresses",
                 config->hport);
@@ -3445,7 +3484,7 @@ static void listen_loop(void)
        */
       if (received_hup_signal)
       {
-         init_error_log(Argv[0], config->logfile, config->debug);
+         init_error_log(Argv[0], config->logfile);
          received_hup_signal = 0;
       }
 #endif
@@ -3520,10 +3559,10 @@ static void listen_loop(void)
 
 #ifdef FEATURE_TOGGLE
       if (global_toggle_state)
+#endif /* def FEATURE_TOGGLE */
       {
          csp->flags |= CSP_FLAG_TOGGLED_ON;
       }
-#endif /* def FEATURE_TOGGLE */
 
       if (run_loader(csp))
       {