[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[or-cvs] add support for CONNECTing through https proxies.



Update of /home2/or/cvsroot/tor/src/or
In directory moria.mit.edu:/home2/arma/work/onion/cvs/tor/src/or

Modified Files:
	config.c connection_or.c directory.c or.h 
Log Message:
add support for CONNECTing through https proxies.
not sure if it works. i don't have an https proxy.


Index: config.c
===================================================================
RCS file: /home2/or/cvsroot/tor/src/or/config.c,v
retrieving revision 1.316
retrieving revision 1.317
diff -u -d -r1.316 -r1.317
--- config.c	22 Feb 2005 23:52:44 -0000	1.316
+++ config.c	24 Feb 2005 10:56:55 -0000	1.317
@@ -131,6 +131,7 @@
   VAR("Group",               STRING,   Group,                NULL),
   VAR("HashedControlPassword",STRING,  HashedControlPassword, NULL),
   VAR("HttpProxy",           STRING,   HttpProxy,            NULL),
+  VAR("HttpsProxy",          STRING,   HttpsProxy,           NULL),
   VAR("HiddenServiceOptions",LINELIST_V, RendConfigLines,    NULL),
   VAR("HiddenServiceDir",    LINELIST_S, RendConfigLines,    NULL),
   VAR("HiddenServicePort",   LINELIST_S, RendConfigLines,    NULL),
@@ -1463,6 +1464,17 @@
     }
   }
 
+  if (options->HttpsProxy) { /* parse it now */
+    if (parse_addr_port(options->HttpsProxy, NULL,
+                        &options->HttpsProxyAddr, &options->HttpsProxyPort) < 0) {
+      log(LOG_WARN,"HttpsProxy failed to parse or resolve. Please fix.");
+      result = -1;
+    }
+    if (options->HttpsProxyPort == 0) { /* give it a default */
+      options->HttpsProxyPort = 443;
+    }
+  }
+
   if (options->HashedControlPassword) {
     if (decode_hashed_password(NULL, options->HashedControlPassword)<0) {
       log_fn(LOG_WARN,"Bad HashedControlPassword: wrong length or bad base64");

Index: connection_or.c
===================================================================
RCS file: /home2/or/cvsroot/tor/src/or/connection_or.c,v
retrieving revision 1.159
retrieving revision 1.160
diff -u -d -r1.159 -r1.160
--- connection_or.c	22 Feb 2005 08:18:35 -0000	1.159
+++ connection_or.c	24 Feb 2005 10:56:55 -0000	1.160
@@ -47,6 +47,56 @@
   return 0;
 }
 
+/** Read conn's inbuf. If the http response from the proxy is all
+ * here, make sure it's good news, and begin the tls handshake. If
+ * it's bad news, close the connection and return -1. Else return 0
+ * and hope for better luck next time.
+ */
+static int
+connection_or_read_proxy_response(connection_t *conn) {
+
+  char *headers;
+  int status_code;
+  time_t date_header;
+  int compression;
+
+  switch (fetch_from_buf_http(conn->inbuf,
+                              &headers, MAX_HEADERS_SIZE,
+                              NULL, NULL, 10000)) {
+    case -1: /* overflow */
+      log_fn(LOG_WARN,"Your https proxy sent back an oversized response. Closing.");
+      return -1;
+    case 0:
+      log_fn(LOG_INFO,"https proxy response not all here yet. Waiting.");
+      return 0;
+    /* case 1, fall through */
+  }
+
+  if (parse_http_response(headers, &status_code, &date_header,
+                          &compression) < 0) {
+    log_fn(LOG_WARN,"Unparseable headers (connecting to '%s'). Closing.",
+           conn->address);
+    tor_free(headers);
+    return -1;
+  }
+
+  if (status_code == 200) {
+    log_fn(LOG_INFO,"https connect successful (to '%s')! Launching tls.",
+           conn->address);
+    if (connection_tls_start_handshake(conn, 0) < 0) {
+      /* TLS handshaking error of some kind. */
+      connection_mark_for_close(conn);
+      return -1;
+    }
+    return 0;
+  }
+  /* else, bad news on the status code */
+  log_fn(LOG_WARN,"The https proxy sent back a bad status code %d. Closing.",
+         status_code);
+  connection_mark_for_close(conn);
+  return -1;
+}
+
 /** Handle any new bytes that have come in on connection <b>conn</b>.
  * If conn is in 'open' state, hand it to
  * connection_or_process_cells_from_inbuf()
@@ -57,9 +107,14 @@
   tor_assert(conn);
   tor_assert(conn->type == CONN_TYPE_OR);
 
-  if (conn->state != OR_CONN_STATE_OPEN)
-    return 0; /* don't do anything */
-  return connection_or_process_cells_from_inbuf(conn);
+  switch(conn->state) {
+    case OR_CONN_STATE_PROXY_READING:
+      return connection_or_read_proxy_response(conn);
+    case OR_CONN_STATE_OPEN:
+      return connection_or_process_cells_from_inbuf(conn);
+    default:
+      return 0; /* don't do anything */
+  }
 }
 
 /** Connection <b>conn</b> has finished writing and has no bytes left on
@@ -76,15 +131,22 @@
 
   assert_connection_ok(conn,0);
 
-  if (conn->state != OR_CONN_STATE_OPEN) {
-    log_fn(LOG_WARN,"BUG: called in unexpected state %d",conn->state);
+  switch(conn->state) {
+    case OR_CONN_STATE_PROXY_FLUSHING:
+      log_fn(LOG_DEBUG,"finished sending CONNECT to proxy.");
+      conn->state = OR_CONN_STATE_PROXY_READING;
+      connection_stop_writing(conn);
+      break;
+    case OR_CONN_STATE_OPEN:
+      connection_stop_writing(conn);
+      break;
+    default:
+      log_fn(LOG_WARN,"BUG: called in unexpected state %d.", conn->state);
 #ifdef TOR_FRAGILE
-    tor_assert(0);
+      tor_assert(0);
 #endif
-    return -1;
+      return -1;
   }
-
-  connection_stop_writing(conn);
   return 0;
 }
 
@@ -99,6 +161,20 @@
   log_fn(LOG_INFO,"OR connect() to router at %s:%u finished.",
          conn->address,conn->port);
 
+  if (get_options()->HttpsProxy) {
+    char buf[1024];
+    char addrbuf[INET_NTOA_BUF_LEN];
+    struct in_addr in;
+
+    in.s_addr = htonl(conn->addr);
+    tor_inet_ntoa(&in, addrbuf, sizeof(addrbuf));
+    tor_snprintf(buf, sizeof(buf), "CONNECT %s:%d HTTP/1.0\r\n\r\n",
+                 addrbuf, conn->port);
+    connection_write_to_buf(buf, strlen(buf), conn);
+    conn->state = OR_CONN_STATE_PROXY_FLUSHING;
+    return 0;
+  }
+
   if (connection_tls_start_handshake(conn, 0) < 0) {
     /* TLS handshaking error of some kind. */
     connection_mark_for_close(conn);
@@ -212,10 +288,11 @@
                                     const char *id_digest) {
   connection_t *conn;
   routerinfo_t *me;
+  or_options_t *options = get_options();
 
   tor_assert(id_digest);
 
-  if (server_mode(get_options()) && (me=router_get_my_routerinfo()) &&
+  if (server_mode(options) && (me=router_get_my_routerinfo()) &&
       !memcmp(me->identity_digest, id_digest,DIGEST_LEN)) {
     log_fn(LOG_WARN,"Bug: Client asked me to connect to myself! Refusing.");
     return NULL;
@@ -238,9 +315,16 @@
   conn->state = OR_CONN_STATE_CONNECTING;
   control_event_or_conn_status(conn, OR_CONN_EVENT_LAUNCHED);
 
+  if (options->HttpsProxy) {
+    /* we shouldn't connect directly. use the https proxy instead. */
+    addr = options->HttpsProxyAddr;
+    port = options->HttpsProxyPort;
+  }
+
   switch (connection_connect(conn, conn->address, addr, port)) {
     case -1:
-      router_mark_as_down(conn->identity_digest);
+      if (!options->HttpsProxy)
+        router_mark_as_down(conn->identity_digest);
       control_event_or_conn_status(conn, OR_CONN_EVENT_FAILED);
       connection_free(conn);
       return NULL;
@@ -252,12 +336,11 @@
     /* case 1: fall through */
   }
 
-  if (connection_tls_start_handshake(conn, 0) >= 0)
-    return conn;
-
-  /* failure */
-  connection_mark_for_close(conn);
-  return NULL;
+  if (connection_or_finished_connecting(conn) < 0) {
+    /* already marked for close */
+    return NULL;
+  }
+  return conn;
 }
 
 /** Begin the tls handshake with <b>conn</b>. <b>receiving</b> is 0 if

Index: directory.c
===================================================================
RCS file: /home2/or/cvsroot/tor/src/or/directory.c,v
retrieving revision 1.213
retrieving revision 1.214
diff -u -d -r1.213 -r1.214
--- directory.c	23 Feb 2005 22:14:34 -0000	1.213
+++ directory.c	24 Feb 2005 10:56:55 -0000	1.214
@@ -62,9 +62,6 @@
 char rend_fetch_url[] = "/tor/rendezvous/";
 #endif
 
-#define MAX_HEADERS_SIZE 50000
-#define MAX_BODY_SIZE 500000
-
 #define ALLOW_DIRECTORY_TIME_SKEW 30*60
 
 /********* END VARIABLES ************/
@@ -497,7 +494,7 @@
  * if the value of the header is not recognized.
  * Otherwise, return -1.
  */
-static int
+int
 parse_http_response(const char *headers, int *code, time_t *date,
                     int *compression)
 {

Index: or.h
===================================================================
RCS file: /home2/or/cvsroot/tor/src/or/or.h,v
retrieving revision 1.538
retrieving revision 1.539
diff -u -d -r1.538 -r1.539
--- or.h	22 Feb 2005 23:52:44 -0000	1.538
+++ or.h	24 Feb 2005 10:56:55 -0000	1.539
@@ -148,6 +148,10 @@
 #define MAX_HEX_NICKNAME_LEN (HEX_DIGEST_LEN+1)
 #define MAX_DIR_SIZE 500000
 
+/* For http parsing */
+#define MAX_HEADERS_SIZE 50000
+#define MAX_BODY_SIZE 500000
+
 #ifdef TOR_PERF
 /** How long do we keep DNS cache entries before purging them? */
 #define MAX_DNS_ENTRY_AGE (150*60)
@@ -220,11 +224,15 @@
 #define _OR_CONN_STATE_MIN 1
 /** State for a connection to an OR: waiting for connect() to finish. */
 #define OR_CONN_STATE_CONNECTING 1
+/** State for a connection to an OR: waiting for proxy command to flush. */
+#define OR_CONN_STATE_PROXY_FLUSHING 2
+/** State for a connection to an OR: waiting for proxy response. */
+#define OR_CONN_STATE_PROXY_READING 3
 /** State for a connection to an OR: SSL is handshaking, not done yet. */
-#define OR_CONN_STATE_HANDSHAKING 2
+#define OR_CONN_STATE_HANDSHAKING 4
 /** State for a connection to an OR: Ready to send/receive cells. */
-#define OR_CONN_STATE_OPEN 3
-#define _OR_CONN_STATE_MAX 3
+#define OR_CONN_STATE_OPEN 5
+#define _OR_CONN_STATE_MAX 5
 
 #define _EXIT_CONN_STATE_MIN 1
 /** State for an exit connection: waiting for response from dns farm. */
@@ -991,6 +999,10 @@
   uint32_t HttpProxyAddr; /**< Parsed IPv4 addr for http proxy, if any */
   uint16_t HttpProxyPort; /**< Parsed port for http proxy, if any */
 
+  char *HttpsProxy; /**< hostname[:port] to use as https proxy, if any */
+  uint32_t HttpsProxyAddr; /**< Parsed IPv4 addr for https proxy, if any */
+  uint16_t HttpsProxyPort; /**< Parsed port for https proxy, if any */
+
   struct config_line_t *DirServers; /**< List of configuration lines
                                      * for directory servers. */
   char *MyFamily; /**< Declared family for this OR. */
@@ -1360,6 +1372,9 @@
                                   size_t payload_len);
 void directory_get_from_dirserver(uint8_t purpose, const char *resource,
                                   int retry_if_no_servers);
+int parse_http_response(const char *headers, int *code, time_t *date,
+                        int *compression);
+
 int connection_dir_reached_eof(connection_t *conn);
 int connection_dir_process_inbuf(connection_t *conn);
 int connection_dir_finished_flushing(connection_t *conn);