Browse Source

Merge remote-tracking branch 'ahf/bugs/22305'

Nick Mathewson 7 years ago
parent
commit
9a50c73104
2 changed files with 73 additions and 15 deletions
  1. 72 15
      src/or/directory.c
  2. 1 0
      src/or/directory.h

+ 72 - 15
src/or/directory.c

@@ -1675,6 +1675,7 @@ directory_send_command(dir_connection_t *conn,
   const char *payload = req->payload;
   const size_t payload_len = req->payload_len;
   const time_t if_modified_since = req->if_modified_since;
+  const int anonymized_connection = dirind_is_anon(req->indirection);
 
   char proxystring[256];
   char hoststring[128];
@@ -1740,11 +1741,13 @@ directory_send_command(dir_connection_t *conn,
     proxystring[0] = 0;
   }
 
-  /* Add Accept-Encoding. */
-  accept_encoding = accept_encoding_header();
-  smartlist_add_asprintf(headers, "Accept-Encoding: %s\r\n",
-                         accept_encoding);
-  tor_free(accept_encoding);
+  if (! anonymized_connection) {
+    /* Add Accept-Encoding. */
+    accept_encoding = accept_encoding_header();
+    smartlist_add_asprintf(headers, "Accept-Encoding: %s\r\n",
+                           accept_encoding);
+    tor_free(accept_encoding);
+  }
 
   /* Add additional headers, if any */
   {
@@ -2199,8 +2202,8 @@ static int handle_response_upload_renddesc_v2(dir_connection_t *,
 static int
 connection_dir_client_reached_eof(dir_connection_t *conn)
 {
-  char *body;
-  char *headers;
+  char *body = NULL;
+  char *headers = NULL;
   char *reason = NULL;
   size_t body_len = 0;
   int status_code;
@@ -2209,10 +2212,15 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
   compress_method_t compression;
   int plausible;
   int skewed = 0;
+  int rv;
   int allow_partial = (conn->base_.purpose == DIR_PURPOSE_FETCH_SERVERDESC ||
                        conn->base_.purpose == DIR_PURPOSE_FETCH_EXTRAINFO ||
                        conn->base_.purpose == DIR_PURPOSE_FETCH_MICRODESC);
   size_t received_bytes;
+  const int anonymized_connection =
+    purpose_needs_anonymity(conn->base_.purpose,
+                            conn->router_purpose,
+                            conn->requested_resource);
 
   received_bytes = connection_get_inbuf_len(TO_CONN(conn));
 
@@ -2236,8 +2244,9 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
                           &compression, &reason) < 0) {
     log_warn(LD_HTTP,"Unparseable headers (server '%s:%d'). Closing.",
              conn->base_.address, conn->base_.port);
-    tor_free(body); tor_free(headers);
-    return -1;
+
+    rv = -1;
+    goto done;
   }
   if (!reason) reason = tor_strdup("[no reason given]");
 
@@ -2311,8 +2320,8 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
     if ((ds = router_get_fallback_dirserver_by_digest(id_digest)))
       ds->fake_status.last_dir_503_at = now;
 
-    tor_free(body); tor_free(headers); tor_free(reason);
-    return -1;
+    rv = -1;
+    goto done;
   }
 
   plausible = body_is_plausible(body, body_len, conn->base_.purpose);
@@ -2340,13 +2349,29 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
                description2,
                (compression>0 && guessed>0)?"  Trying both.":"");
     }
+
     /* Try declared compression first if we can.
-     * tor_compress_supports_method() also returns true for NO_METHOD. */
+     * tor_compress_supports_method() also returns true for NO_METHOD.
+     * Ensure that the server is not sending us data compressed using a
+     * compression method that is not allowed for anonymous connections. */
+    if (anonymized_connection &&
+        ! allowed_anonymous_connection_compression_method(compression)) {
+      rv = -1;
+      goto done;
+    }
+
     if (tor_compress_supports_method(compression))
       tor_uncompress(&new_body, &new_len, body, body_len, compression,
                      !allow_partial, LOG_PROTOCOL_WARN);
+
     /* Okay, if that didn't work, and we think that it was compressed
      * differently, try that. */
+    if (anonymized_connection &&
+        ! allowed_anonymous_connection_compression_method(guessed)) {
+      rv = -1;
+      goto done;
+    }
+
     if (!new_body && tor_compress_supports_method(guessed) &&
         compression != guessed)
       tor_uncompress(&new_body, &new_len, body, body_len, guessed,
@@ -2357,8 +2382,8 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
       log_fn(LOG_PROTOCOL_WARN, LD_HTTP,
              "Unable to decompress HTTP body (server '%s:%d').",
              conn->base_.address, conn->base_.port);
-      tor_free(body); tor_free(headers); tor_free(reason);
-      return -1;
+      rv = -1;
+      goto done;
     }
     if (new_body) {
       tor_free(body);
@@ -2367,7 +2392,6 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
     }
   }
 
-  int rv;
   response_handler_args_t args;
   memset(&args, 0, sizeof(args));
   args.status_code = status_code;
@@ -2416,6 +2440,8 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
       rv = -1;
       break;
   }
+
+ done:
   tor_free(body);
   tor_free(headers);
   tor_free(reason);
@@ -3331,6 +3357,14 @@ static compress_method_t srv_meth_pref_streaming_compression[] = {
   NO_METHOD
 };
 
+/** Array of allowed compression methods to use (if supported) when receiving a
+ * response from a request that was required to be anonymous. */
+static compress_method_t client_meth_allowed_anonymous_compression[] = {
+  ZLIB_METHOD,
+  GZIP_METHOD,
+  NO_METHOD
+};
+
 /** Parse the compression methods listed in an Accept-Encoding header <b>h</b>,
  * and convert them to a bitfield where compression method x is supported if
  * and only if 1 &lt;&lt; x is set in the bitfield. */
@@ -3830,6 +3864,29 @@ find_best_compression_method(unsigned compression_methods, int stream)
   return NO_METHOD;
 }
 
+/** Check if the given compression method is allowed for a connection that is
+ * supposed to be anonymous. Returns 1 if the compression method is allowed,
+ * otherwise 0. */
+STATIC int
+allowed_anonymous_connection_compression_method(compress_method_t method)
+{
+  unsigned u;
+
+  for (u = 0; u < ARRAY_LENGTH(client_meth_allowed_anonymous_compression);
+       ++u) {
+    compress_method_t allowed_method =
+      client_meth_allowed_anonymous_compression[u];
+
+    if (! tor_compress_supports_method(allowed_method))
+      continue;
+
+    if (method == allowed_method)
+      return 1;
+  }
+
+  return 0;
+}
+
 /** Encodes the results of parsing a consensus request to figure out what
  * consensus, and possibly what diffs, the user asked for. */
 typedef struct {

+ 1 - 0
src/or/directory.h

@@ -163,6 +163,7 @@ STATIC int handle_get_hs_descriptor_v3(dir_connection_t *conn,
                                        const struct get_handler_args_t *args);
 STATIC int directory_handle_command(dir_connection_t *conn);
 STATIC char *accept_encoding_header(void);
+STATIC int allowed_anonymous_connection_compression_method(compress_method_t);
 
 #endif