Merge branch 'maint-0.3.1'

This commit is contained in:
Nick Mathewson 2017-06-29 11:38:06 -04:00
commit 3781678a3c
4 changed files with 135 additions and 84 deletions

4
changes/bug22670 Normal file
View File

@ -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
changes/bug22670_02 Normal file
View File

@ -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
changes/bug22670_03 Normal file
View File

@ -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.

View File

@ -2191,6 +2191,123 @@ static int handle_response_fetch_renddesc_v2(dir_connection_t *,
static int handle_response_upload_renddesc_v2(dir_connection_t *, static int handle_response_upload_renddesc_v2(dir_connection_t *,
const response_handler_args_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 /** We are a client, and we've finished reading the server's
* response. Parse it and act appropriately. * response. Parse it and act appropriately.
* *
@ -2211,7 +2328,6 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
time_t date_header = 0; time_t date_header = 0;
long apparent_skew; long apparent_skew;
compress_method_t compression; compress_method_t compression;
int plausible;
int skewed = 0; int skewed = 0;
int rv; int rv;
int allow_partial = (conn->base_.purpose == DIR_PURPOSE_FETCH_SERVERDESC || int allow_partial = (conn->base_.purpose == DIR_PURPOSE_FETCH_SERVERDESC ||
@ -2325,91 +2441,12 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
goto done; goto done;
} }
plausible = body_is_plausible(body, body_len, conn->base_.purpose); if (dir_client_decompress_response_body(&body, &body_len,
if (compression != NO_METHOD || !plausible) { conn, compression, anonymized_connection) < 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_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; rv = -1;
goto done; 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;
}
}
response_handler_args_t args; response_handler_args_t args;
memset(&args, 0, sizeof(args)); memset(&args, 0, sizeof(args));
args.status_code = status_code; args.status_code = status_code;