Add support for Tor's optimistic-data SOCKS extension
authorFabian Keil <fk@fabiankeil.de>
Fri, 7 Dec 2012 12:45:20 +0000 (12:45 +0000)
committerFabian Keil <fk@fabiankeil.de>
Fri, 7 Dec 2012 12:45:20 +0000 (12:45 +0000)
.. which can reduce the latency for requests on newly
created connections.

Currently only the headers are sent optimistically and
only if the client request has already been read completely
which rules out requests with large bodies.

cgi.c
cgisimple.c
filters.c
gateway.c
jcc.c
loadcfg.c
project.h

diff --git a/cgi.c b/cgi.c
index 950d885..f81443e 100644 (file)
--- a/cgi.c
+++ b/cgi.c
@@ -1,4 +1,4 @@
-const char cgi_rcs[] = "$Id: cgi.c,v 1.156 2012/10/21 12:54:15 fabiankeil Exp $";
+const char cgi_rcs[] = "$Id: cgi.c,v 1.157 2012/11/09 10:47:42 fabiankeil Exp $";
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/cgi.c,v $
@@ -978,6 +978,9 @@ struct http_response *error_response(struct client_state *csp,
          case SOCKS_5:
             socks_type = "socks5-";
             break;
+         case SOCKS_5T:
+            socks_type = "socks5t-";
+            break;
          default:
             log_error(LOG_LEVEL_FATAL, "Unknown socks type: %d.", fwd->type);
       }
index c1758b9..7855fa0 100644 (file)
@@ -1,4 +1,4 @@
-const char cgisimple_rcs[] = "$Id: cgisimple.c,v 1.116 2012/10/21 12:39:27 fabiankeil Exp $";
+const char cgisimple_rcs[] = "$Id: cgisimple.c,v 1.117 2012/10/21 12:55:29 fabiankeil Exp $";
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/cgisimple.c,v $
@@ -1408,6 +1408,9 @@ jb_err cgi_show_url_info(struct client_state *csp,
                   case SOCKS_5:
                      socks_type = "socks5";
                      break;
+                  case SOCKS_5T:
+                     socks_type = "socks5t";
+                     break;
                   default:
                      log_error(LOG_LEVEL_FATAL, "Unknown socks type: %d.", fwd->type);
                }
index a7f622a..60d420f 100644 (file)
--- a/filters.c
+++ b/filters.c
@@ -1,4 +1,4 @@
-const char filters_rcs[] = "$Id: filters.c,v 1.174 2012/10/21 12:35:15 fabiankeil Exp $";
+const char filters_rcs[] = "$Id: filters.c,v 1.175 2012/10/21 12:58:03 fabiankeil Exp $";
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/filters.c,v $
@@ -2158,6 +2158,11 @@ const static struct forward_spec *get_forward_override_settings(struct client_st
          fwd->type = SOCKS_5;
          socks_proxy = vec[1];
       }
+      else if (!strcasecmp(vec[0], "forward-socks5t"))
+      {
+         fwd->type = SOCKS_5T;
+         socks_proxy = vec[1];
+      }
 
       if (NULL != socks_proxy)
       {
index ae706cf..81b9b81 100644 (file)
--- a/gateway.c
+++ b/gateway.c
@@ -1,4 +1,4 @@
-const char gateway_rcs[] = "$Id: gateway.c,v 1.91 2012/10/21 12:56:38 fabiankeil Exp $";
+const char gateway_rcs[] = "$Id: gateway.c,v 1.92 2012/10/23 10:16:52 fabiankeil Exp $";
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/gateway.c,v $
@@ -66,6 +66,8 @@ const char gateway_rcs[] = "$Id: gateway.c,v 1.91 2012/10/21 12:56:38 fabiankeil
 #include "jbsockets.h"
 #include "gateway.h"
 #include "miscutil.h"
+#include "list.h"
+
 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
 #ifdef HAVE_POLL
 #ifdef __GLIBC__
@@ -639,6 +641,7 @@ jb_socket forwarded_connect(const struct forward_spec * fwd,
          sfd = socks4_connect(fwd, dest_host, dest_port, csp);
          break;
       case SOCKS_5:
+      case SOCKS_5T:
          sfd = socks5_connect(fwd, dest_host, dest_port, csp);
          break;
       default:
@@ -964,7 +967,7 @@ static jb_socket socks5_connect(const struct forward_spec *fwd,
       err = 1;
    }
 
-   if (fwd->type != SOCKS_5)
+   if ((fwd->type != SOCKS_5) && (fwd->type != SOCKS_5T))
    {
       /* Should never get here */
       log_error(LOG_LEVEL_FATAL,
@@ -1078,6 +1081,43 @@ static jb_socket socks5_connect(const struct forward_spec *fwd,
       return(JB_INVALID_SOCKET);
    }
 
+   /*
+    * Optimistically send the request headers with the initial
+    * request if the user requested use of Tor extensions, the
+    * CONNECT method isn't being used (in which case the client
+    * doesn't send data until it gets our 200 response) and the
+    * client request has been already read completely.
+    *
+    * Not optimistically sending the request body (if there is one)
+    * makes it easier to implement, but isn't an actual requirement.
+    */
+   if ((fwd->type == SOCKS_5T) && (csp->http->ssl == 0)
+      && (csp->flags & CSP_FLAG_CLIENT_REQUEST_COMPLETELY_READ))
+   {
+      char *client_headers = list_to_text(csp->headers);
+      size_t header_length;
+
+      if (client_headers == NULL)
+      {
+         log_error(LOG_LEVEL_FATAL, "Out of memory rebuilding client headers");
+      }
+      list_remove_all(csp->headers);
+      header_length= strlen(client_headers);
+
+      log_error(LOG_LEVEL_CONNECT,
+         "Optimistically sending %d bytes of client headers intended for %s",
+         header_length, csp->http->hostport);
+
+      if (write_socket(sfd, client_headers, header_length))
+      {
+         log_error(LOG_LEVEL_CONNECT,
+            "optimistically writing header to: %s failed: %E", csp->http->hostport);
+         freez(client_headers);
+         return(JB_INVALID_SOCKET);
+      }
+      freez(client_headers);
+   }
+
    server_size = read_socket(sfd, sbuf, sizeof(sbuf));
    if (server_size != sizeof(sbuf))
    {
diff --git a/jcc.c b/jcc.c
index 6967ad8..33e406e 100644 (file)
--- a/jcc.c
+++ b/jcc.c
@@ -1,4 +1,4 @@
-const char jcc_rcs[] = "$Id: jcc.c,v 1.418 2012/12/07 12:43:05 fabiankeil Exp $";
+const char jcc_rcs[] = "$Id: jcc.c,v 1.419 2012/12/07 12:43:55 fabiankeil Exp $";
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/jcc.c,v $
@@ -1920,7 +1920,12 @@ static void chat(struct client_state *csp)
 
    csp->server_connection.requests_sent_total++;
 
-   if (fwd->forward_host || (http->ssl == 0))
+   if ((fwd->type == SOCKS_5T) && (NULL == csp->headers->first))
+   {
+      /* Client headers have been sent optimistically */
+      assert(csp->headers->last == NULL);
+   }
+   else if (fwd->forward_host || (http->ssl == 0))
    {
       int write_failure;
       hdr = list_to_text(csp->headers);
@@ -1978,6 +1983,7 @@ static void chat(struct client_state *csp)
 
    log_error(LOG_LEVEL_CONNECT, "to %s successful", http->hostport);
 
+   /* XXX: should the time start earlier for optimistically sent data? */
    csp->server_connection.request_sent = time(NULL);
 
    maxfd = (csp->cfd > csp->server_connection.sfd) ?
index f3bec21..a5bc55d 100644 (file)
--- a/loadcfg.c
+++ b/loadcfg.c
@@ -1,4 +1,4 @@
-const char loadcfg_rcs[] = "$Id: loadcfg.c,v 1.133 2012/10/21 12:32:21 fabiankeil Exp $";
+const char loadcfg_rcs[] = "$Id: loadcfg.c,v 1.134 2012/10/21 12:53:33 fabiankeil Exp $";
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/loadcfg.c,v $
@@ -140,6 +140,7 @@ static struct file_list *current_configfile = NULL;
 #define hash_forward_socks4              3963965521U /* "forward-socks4" */
 #define hash_forward_socks4a             2639958518U /* "forward-socks4a" */
 #define hash_forward_socks5              3963965522U /* "forward-socks5" */
+#define hash_forward_socks5t             2639958542U /* "forward-socks5t" */
 #define hash_forwarded_connect_retries    101465292U /* "forwarded-connect-retries" */
 #define hash_handle_as_empty_returns_ok  1444873247U /* "handle-as-empty-doc-returns-ok" */
 #define hash_hostname                      10308071U /* "hostname" */
@@ -1013,6 +1014,7 @@ struct configuration_spec * load_config(void)
  * *************************************************************************/
          case hash_forward_socks4a:
          case hash_forward_socks5:
+         case hash_forward_socks5t:
             strlcpy(tmp, arg, sizeof(tmp));
             vec_count = ssplit(tmp, " \t", vec, SZ(vec));
 
@@ -1039,10 +1041,15 @@ struct configuration_spec * load_config(void)
             {
                cur_fwd->type = SOCKS_4A;
             }
-            else
+            else if (directive_hash == hash_forward_socks5)
             {
                cur_fwd->type = SOCKS_5;
             }
+            else
+            {
+               assert(directive_hash == hash_forward_socks5t);
+               cur_fwd->type = SOCKS_5T;
+            }
 
             /* Save the URL pattern */
             if (create_url_spec(cur_fwd->url, vec[0]))
index eba76a6..b880241 100644 (file)
--- 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.193 2012/11/24 13:55:51 fabiankeil Exp $"
+#define PROJECT_H_VERSION "$Id: project.h,v 1.194 2012/12/07 12:43:55 fabiankeil Exp $"
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/project.h,v $
@@ -645,6 +645,8 @@ enum forwarder_type {
    SOCKS_4A   = 41,
    /**< SOCKS 5 with hostnames, DNS resolution is done by the SOCKS server */
    SOCKS_5    = 50,
+   /**< Like SOCKS5, but uses non-standard Tor extensions (currently only optimistic data) */
+   SOCKS_5T,
 };
 
 /*