Browse Source

Merge remote-tracking branch 'public/bug22670_031' into maint-0.3.1

Nick Mathewson 6 years ago
parent
commit
31a08ba26f
4 changed files with 135 additions and 84 deletions
  1. 4 0
      changes/bug22670
  2. 4 0
      changes/bug22670_02
  3. 6 0
      changes/bug22670_03
  4. 121 84
      src/or/directory.c

+ 4 - 0
changes/bug22670

@@ -0,0 +1,4 @@
+  o Minor bugfixes (logging, compression):
+    - When decompressing, do not warn if we fail to decompress using a
+      compression method that we merely guessed. Fixes part of
+      bug 22670; bugfix on 0.1.1.14-alpha.

+ 4 - 0
changes/bug22670_02

@@ -0,0 +1,4 @@
+  o Minor bugfixes (logging, compression):
+   - When decompressing, treat mismatch between content-encoding and
+      actual compression type as a protocol warning. Fixes part of bug
+      22670; bugfix on 0.1.1.9-alpha.

+ 6 - 0
changes/bug22670_03

@@ -0,0 +1,6 @@
+  o Minor bugfixes (compression):
+    - When decompressing an object received over an anonymous directory
+      connection, if we have already successfully decompressed it using an
+      acceptable compression method, do not reject it for looking like an
+      unacceptable compression method. Fixes part of bug 22670; bugfix on
+      0.3.1.1-alpha.

+ 121 - 84
src/or/directory.c

@@ -2191,6 +2191,123 @@ static int handle_response_fetch_renddesc_v2(dir_connection_t *,
 static int handle_response_upload_renddesc_v2(dir_connection_t *,
                                               const response_handler_args_t *);
 
+static int
+dir_client_decompress_response_body(char **bodyp, size_t *bodylenp,
+                                    dir_connection_t *conn,
+                                    compress_method_t compression,
+                                    int anonymized_connection)
+{
+  int rv = 0;
+  const char *body = *bodyp;
+  size_t body_len = *bodylenp;
+  int allow_partial = (conn->base_.purpose == DIR_PURPOSE_FETCH_SERVERDESC ||
+                       conn->base_.purpose == DIR_PURPOSE_FETCH_EXTRAINFO ||
+                       conn->base_.purpose == DIR_PURPOSE_FETCH_MICRODESC);
+
+  int plausible = body_is_plausible(body, body_len, conn->base_.purpose);
+
+  if (plausible && compression == NO_METHOD) {
+    return 0;
+  }
+
+  int severity = LOG_DEBUG;
+  char *new_body = NULL;
+  size_t new_len = 0;
+  const char *description1, *description2;
+  int want_to_try_both = 0;
+  int tried_both = 0;
+  compress_method_t guessed = detect_compression_method(body, body_len);
+
+  description1 = compression_method_get_human_name(compression);
+
+  if (BUG(description1 == NULL))
+    description1 = compression_method_get_human_name(UNKNOWN_METHOD);
+
+  if (guessed == UNKNOWN_METHOD && !plausible)
+    description2 = "confusing binary junk";
+  else
+    description2 = compression_method_get_human_name(guessed);
+
+  /* Tell the user if we don't believe what we're told about compression.*/
+  want_to_try_both = (compression == UNKNOWN_METHOD ||
+                      guessed != compression);
+  if (want_to_try_both) {
+    severity = LOG_PROTOCOL_WARN;
+  }
+
+  tor_log(severity, LD_HTTP,
+          "HTTP body from server '%s:%d' was labeled as %s, "
+          "%s it seems to be %s.%s",
+          conn->base_.address, conn->base_.port, description1,
+          guessed != compression?"but":"and",
+          description2,
+          (compression>0 && guessed>0 && want_to_try_both)?
+          "  Trying both.":"");
+
+  /* Try declared compression first if we can.
+   * 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)) {
+    warn_disallowed_anonymous_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);
+    if (new_body) {
+      /* We succeeded with the declared compression method. Great! */
+      rv = 0;
+      goto done;
+    }
+  }
+
+  /* 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)) {
+    warn_disallowed_anonymous_compression_method(guessed);
+    rv = -1;
+    goto done;
+  }
+
+  if (tor_compress_supports_method(guessed) &&
+      compression != guessed) {
+    tor_uncompress(&new_body, &new_len, body, body_len, guessed,
+                   !allow_partial, LOG_INFO);
+    tried_both = 1;
+  }
+  /* If we're pretty sure that we have a compressed directory, and
+   * we didn't manage to uncompress it, then warn and bail. */
+  if (!plausible && !new_body) {
+    log_fn(LOG_PROTOCOL_WARN, LD_HTTP,
+           "Unable to decompress HTTP body (tried %s%s%s, server '%s:%d').",
+           description1,
+           tried_both?" and ":"",
+           tried_both?description2:"",
+           conn->base_.address, conn->base_.port);
+    rv = -1;
+    goto done;
+  }
+
+ done:
+  if (new_body) {
+    if (rv == 0) {
+      /* success! */
+      tor_free(*bodyp);
+      *bodyp = new_body;
+      *bodylenp = new_len;
+    } else {
+      tor_free(new_body);
+    }
+  }
+
+  return rv;
+}
+
 /** We are a client, and we've finished reading the server's
  * response. Parse it and act appropriately.
  *
@@ -2211,7 +2328,6 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
   time_t date_header = 0;
   long apparent_skew;
   compress_method_t compression;
-  int plausible;
   int skewed = 0;
   int rv;
   int allow_partial = (conn->base_.purpose == DIR_PURPOSE_FETCH_SERVERDESC ||
@@ -2325,89 +2441,10 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
     goto done;
   }
 
-  plausible = body_is_plausible(body, body_len, conn->base_.purpose);
-  if (compression != NO_METHOD || !plausible) {
-    int severity = LOG_DEBUG;
-    char *new_body = NULL;
-    size_t new_len = 0;
-    const char *description1, *description2;
-    int want_to_try_both = 0;
-    int tried_both = 0;
-    compress_method_t guessed = detect_compression_method(body, body_len);
-
-    description1 = compression_method_get_human_name(compression);
-
-    if (BUG(description1 == NULL))
-      description1 = compression_method_get_human_name(UNKNOWN_METHOD);
-
-    if (guessed == UNKNOWN_METHOD && !plausible)
-      description2 = "confusing binary junk";
-    else
-      description2 = compression_method_get_human_name(guessed);
-
-    /* Tell the user if we don't believe what we're told about compression.*/
-    want_to_try_both = (compression == UNKNOWN_METHOD ||
-                        guessed != compression);
-    if (want_to_try_both) {
-      severity = LOG_INFO;
-    }
-
-    tor_log(severity, LD_HTTP,
-            "HTTP body from server '%s:%d' was labeled as %s, "
-            "%s it seems to be %s.%s",
-            conn->base_.address, conn->base_.port, description1,
-            guessed != compression?"but":"and",
-            description2,
-            (compression>0 && guessed>0 && want_to_try_both)?
-            "  Trying both.":"");
-
-    /* Try declared compression first if we can.
-     * 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)) {
-      warn_disallowed_anonymous_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)) {
-      warn_disallowed_anonymous_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,
-                     !allow_partial, LOG_PROTOCOL_WARN);
-      tried_both = 1;
-    }
-    /* If we're pretty sure that we have a compressed directory, and
-     * we didn't manage to uncompress it, then warn and bail. */
-    if (!plausible && !new_body) {
-      log_fn(LOG_PROTOCOL_WARN, LD_HTTP,
-             "Unable to decompress HTTP body (tried %s%s%s, server '%s:%d').",
-             description1,
-             tried_both?" and ":"",
-             tried_both?description2:"",
-             conn->base_.address, conn->base_.port);
-      rv = -1;
-      goto done;
-    }
-    if (new_body) {
-      tor_free(body);
-      body = new_body;
-      body_len = new_len;
-    }
+  if (dir_client_decompress_response_body(&body, &body_len,
+                             conn, compression, anonymized_connection) < 0) {
+    rv = -1;
+    goto done;
   }
 
   response_handler_args_t args;