diff --git a/ChangeLog b/ChangeLog index e9625aff7..f96606549 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,12 @@ Changes in version 0.2.1.9-alpha - 200?-??-?? - Fix a logic error that would automatically reject all but the first configured DNS server. Bugfix on 0.2.1.5-alpha. Possible fix for part of bug 813/868. Bug spotted by coderman. + - When a stream at an exit relay is in state "resolving" or + "connecting" and it receives an "end" relay cell, the exit relay + would silently ignore the end cell and not close the stream. If + the client never closes the circuit, then the exit relay never + closes the TCP connection. Bug introduced in Tor 0.1.2.1-alpha; + reported by "wood". o Minor features: - Give a better error message when an overzealous init script says, diff --git a/src/or/relay.c b/src/or/relay.c index e5d6d73be..0158f5122 100644 --- a/src/or/relay.c +++ b/src/or/relay.c @@ -594,11 +594,12 @@ edge_reason_is_retriable(int reason) reason == END_STREAM_REASON_MISC; } -/** Called when we receive an END cell on a stream that isn't open yet. +/** Called when we receive an END cell on a stream that isn't open yet, + * from the client side. * Arguments are as for connection_edge_process_relay_cell(). */ static int -connection_edge_process_end_not_open( +connection_ap_process_end_not_open( relay_header_t *rh, cell_t *cell, origin_circuit_t *circ, edge_connection_t *conn, crypt_path_t *layer_hint) { @@ -608,8 +609,7 @@ connection_edge_process_end_not_open( int control_reason = reason | END_STREAM_REASON_FLAG_REMOTE; (void) layer_hint; /* unused */ - if (rh->length > 0 && edge_reason_is_retriable(reason) && - conn->_base.type == CONN_TYPE_AP) { + if (rh->length > 0 && edge_reason_is_retriable(reason)) { log_info(LD_APP,"Address '%s' refused due to '%s'. Considering retrying.", safe_str(conn->socks_request->address), stream_end_reason_to_string(reason)); @@ -725,17 +725,10 @@ connection_edge_process_end_not_open( log_info(LD_APP, "Edge got end (%s) before we're connected. Marking for close.", stream_end_reason_to_string(rh->length > 0 ? reason : -1)); - if (conn->_base.type == CONN_TYPE_AP) { - circuit_log_path(LOG_INFO,LD_APP,circ); - /* need to test because of detach_retriable*/ - if (!conn->_base.marked_for_close) - connection_mark_unattached_ap(conn, control_reason); - } else { - /* we just got an 'end', don't need to send one */ - conn->_base.edge_has_sent_end = 1; - conn->end_reason = control_reason; - connection_mark_for_close(TO_CONN(conn)); - } + circuit_log_path(LOG_INFO,LD_APP,circ); + /* need to test because of detach_retriable*/ + if (!conn->_base.marked_for_close) + connection_mark_unattached_ap(conn, control_reason); return 0; } @@ -767,12 +760,18 @@ connection_edge_process_relay_cell_not_open( edge_connection_t *conn, crypt_path_t *layer_hint) { if (rh->command == RELAY_COMMAND_END) { - if (CIRCUIT_IS_ORIGIN(circ)) - return connection_edge_process_end_not_open(rh, cell, - TO_ORIGIN_CIRCUIT(circ), conn, - layer_hint); - else + if (CIRCUIT_IS_ORIGIN(circ) && conn->_base.type == CONN_TYPE_AP) { + return connection_ap_process_end_not_open(rh, cell, + TO_ORIGIN_CIRCUIT(circ), conn, + layer_hint); + } else { + /* we just got an 'end', don't need to send one */ + conn->_base.edge_has_sent_end = 1; + conn->end_reason = *(cell->payload+RELAY_HEADER_SIZE) | + END_STREAM_REASON_FLAG_REMOTE; + connection_mark_for_close(TO_CONN(conn)); return 0; + } } if (conn->_base.type == CONN_TYPE_AP &&