diff --git a/ChangeLog b/ChangeLog index 087f81e27a..1a18101b4a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,7 +6,9 @@ Changes in version 0.1.2.3-alpha - 2006-10-?? o Minor features, controller: - Add a REASON field to CIRC events; for backward compatibility, this field is sent only to controllers that have enabled the extended - event format. (Patch from Mike Perry) + event format. Also, add additional reason codes to explain why a + given circuit has been destroyed or truncated. (Patches from Mike + Perry) o Security bugfixes: - When the user sends a NEWNYM signal, clear the client-side DNS diff --git a/doc/control-spec.txt b/doc/control-spec.txt index 0d06a6423a..375e3eab72 100644 --- a/doc/control-spec.txt +++ b/doc/control-spec.txt @@ -777,16 +777,17 @@ $Id$ Reason = "NONE" / "TORPROTOCOL" / "INTERNAL" / "REQUESTED" / "HIBERNATING" / "RESOURCELIMIT" / "CONNECTFAILED" / - "OR_IDENTITY" / "OR_CONN_CLOSED" + "OR_IDENTITY" / "OR_CONN_CLOSED" / "TIMEOUT" / + "FINISHED" / "DESTROYED" / "NOPATH" / "NOSUCHSERVICE" The path is provided only when the circuit has been extended at least one hop. The "REASON" field is provided only for FAILED and CLOSED events, and only if extended events are enabled (see 3.19). Clients MUST accept reasons - not listed above. + not listed above. Reasons are as given in tor-spec.txt, except for: - [XXXX Explain what the reasons mean.] + NOPATH (Not enough nodes to make circuit) 4.1.2. Stream status changed diff --git a/doc/tor-spec.txt b/doc/tor-spec.txt index cf6f78fb44..2ebd350db5 100644 --- a/doc/tor-spec.txt +++ b/doc/tor-spec.txt @@ -228,7 +228,7 @@ TODO: associated with. The 'Command' field holds one of the following values: - 0 -- PADDING (Padding) (See Sec 7.2) + 0 -- PADDING (Padding) (See Sec 7.2) 1 -- CREATE (Create a circuit) (See Sec 5.1) 2 -- CREATED (Acknowledge create) (See Sec 5.1) 3 -- RELAY (End-to-end data) (See Sec 5.5 and 6) @@ -563,6 +563,10 @@ TODO: as expected.) 8 -- OR_CONN_CLOSED (The OR connection that was carrying this circuit died.) + 9 -- FINISHED (The circuit has expired for being dirty or old.) + 10 -- TIMEOUT (Circuit construction took too long) + 11 -- DESTROYED (The circuit was destroyed w/o client TRUNCATE) + 12 -- NOSUCHSERVICE (Request for unknown hidden service) [Versions of Tor prior to 0.1.0.11 didn't send reasons; implementations MUST accept empty TRUNCATED and DESTROY cells.] diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index 8d76e6a341..239c4e198c 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -305,8 +305,7 @@ circuit_establish_circuit(uint8_t purpose, extend_info_t *info, if (onion_pick_cpath_exit(circ, info) < 0 || onion_populate_cpath(circ) < 0) { - /* XXX should there be a 'couldn't build a path' reason? */ - circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL); + circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_NOPATH); return NULL; } diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c index 35514e3783..37b3717ff2 100644 --- a/src/or/circuitlist.c +++ b/src/or/circuitlist.c @@ -780,7 +780,7 @@ circuit_mark_all_unused_circs(void) if (CIRCUIT_IS_ORIGIN(circ) && !circ->marked_for_close && !circ->timestamp_dirty) - circuit_mark_for_close(circ, END_CIRC_REASON_REQUESTED); + circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED); } } @@ -843,7 +843,7 @@ _circuit_mark_for_close(circuit_t *circ, int reason, int line, file, line, circ->purpose); } reason = END_CIRC_REASON_NONE; - } else if (CIRCUIT_IS_ORIGIN(circ) && reason != END_CIRC_REASON_NONE) { + } else if (CIRCUIT_IS_ORIGIN(circ) && reason < _END_CIRC_REASON_MIN) { /* We don't send reasons when closing circuits at the origin, but we want * to track them anyway so we can give them to the controller. */ reason = END_CIRC_REASON_NONE; diff --git a/src/or/circuituse.c b/src/or/circuituse.c index 9e3de14a8e..84b642fbe4 100644 --- a/src/or/circuituse.c +++ b/src/or/circuituse.c @@ -265,8 +265,7 @@ circuit_expire_building(time_t now) circuit_state_to_string(victim->state), victim->purpose); circuit_log_path(LOG_INFO,LD_CIRC,TO_ORIGIN_CIRCUIT(victim)); - /* XXXX Should there be a timeout reason? CONNECTFAILED isn't right. */ - circuit_mark_for_close(victim, END_CIRC_REASON_CONNECTFAILED); + circuit_mark_for_close(victim, END_CIRC_REASON_TIMEOUT); } } @@ -584,8 +583,7 @@ circuit_expire_old_circuits(time_t now) log_debug(LD_CIRC, "Closing n_circ_id %d (dirty %d secs ago, purp %d)", circ->n_circ_id, (int)(now - circ->timestamp_dirty), circ->purpose); - /* XXXX Should there be a timeout reason? REQUESTED isn't right. */ - circuit_mark_for_close(circ, END_CIRC_REASON_REQUESTED); + circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED); } else if (!circ->timestamp_dirty && circ->state == CIRCUIT_STATE_OPEN && circ->purpose == CIRCUIT_PURPOSE_C_GENERAL) { @@ -593,8 +591,7 @@ circuit_expire_old_circuits(time_t now) log_debug(LD_CIRC, "Closing circuit that has been unused for %d seconds.", (int)(now - circ->timestamp_created)); - /* XXXX Should there be a timeout reason? REQUESTED isn't right. */ - circuit_mark_for_close(circ, END_CIRC_REASON_REQUESTED); + circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED); } } } diff --git a/src/or/command.c b/src/or/command.c index 8a45ff46b5..ff10d35892 100644 --- a/src/or/command.c +++ b/src/or/command.c @@ -379,18 +379,12 @@ command_process_destroy_cell(cell_t *cell, or_connection_t *conn) circuit_set_n_circid_orconn(circ, 0, NULL); if (CIRCUIT_IS_ORIGIN(circ)) { /* Prevent arbitrary destroys from going unnoticed by controller */ - /* XXXX Not quite right; what we want is to tell the controller the - * exact reason that we were asked to close, but tell it that we - * closed because we were asked. Anything else is not accurate. - * OR_CONN_CLOSED is certainly wrong, since a destroy doesn't mean - * that the underlying OR connection got closed. -NM */ -#if 0 if (reason == END_CIRC_AT_ORIGIN || reason == END_CIRC_REASON_NONE || + reason == END_CIRC_REASON_FINISHED || reason == END_CIRC_REASON_REQUESTED) { - reason = END_CIRC_REASON_OR_CONN_CLOSED; + reason = END_CIRC_REASON_DESTROYED; } -#endif circuit_mark_for_close(circ, reason); } else { char payload[1]; diff --git a/src/or/config.c b/src/or/config.c index 7ba1e22b01..4ca0406b9c 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -3666,6 +3666,7 @@ static const struct { { "1.1", LE_11 }, { "1.1a", LE_11A }, { "1.1b", LE_11B }, + { "1.2", LE_12 }, { NULL, 0 } }; diff --git a/src/or/control.c b/src/or/control.c index 18d59607da..8001fe216e 100644 --- a/src/or/control.c +++ b/src/or/control.c @@ -2825,6 +2825,16 @@ circuit_end_reason_to_string(int reason) return "REASON=OR_IDENTITY"; case END_CIRC_REASON_OR_CONN_CLOSED: return "REASON=OR_CONN_CLOSED"; + case END_CIRC_REASON_FINISHED: + return "REASON=FINISHED"; + case END_CIRC_REASON_TIMEOUT: + return "REASON=TIMEOUT"; + case END_CIRC_REASON_DESTROYED: + return "REASON=DESTROYED"; + case END_CIRC_REASON_NOPATH: + return "REASON=NOPATH"; + case END_CIRC_REASON_NOSUCHSERVICE: + return "REASON=NOSUCHSERVICE"; default: log_warn(LD_BUG, "Unrecognized reason code %d", (int)reason); return NULL; diff --git a/src/or/or.h b/src/or/or.h index 763ce2dbee..7a5f1632d4 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -494,7 +494,9 @@ typedef enum { #define RESOLVED_TYPE_ERROR 0xF1 /* DOCDOC We should document the meaning of these. */ -#define END_CIRC_AT_ORIGIN -1 +/* Negative reasons are internal */ +#define END_CIRC_REASON_NOPATH -2 +#define END_CIRC_AT_ORIGIN -1 #define _END_CIRC_REASON_MIN 0 #define END_CIRC_REASON_NONE 0 #define END_CIRC_REASON_TORPROTOCOL 1 @@ -505,7 +507,11 @@ typedef enum { #define END_CIRC_REASON_CONNECTFAILED 6 #define END_CIRC_REASON_OR_IDENTITY 7 #define END_CIRC_REASON_OR_CONN_CLOSED 8 -#define _END_CIRC_REASON_MAX 8 +#define END_CIRC_REASON_FINISHED 9 +#define END_CIRC_REASON_TIMEOUT 10 +#define END_CIRC_REASON_DESTROYED 11 +#define END_CIRC_REASON_NOSUCHSERVICE 12 +#define _END_CIRC_REASON_MAX 12 /** Length of 'y' portion of 'y.onion' URL. */ #define REND_SERVICE_ID_LEN 16 diff --git a/src/or/rendclient.c b/src/or/rendclient.c index 078773b1e8..7297f1b981 100644 --- a/src/or/rendclient.c +++ b/src/or/rendclient.c @@ -211,7 +211,7 @@ rend_client_introduction_acked(origin_circuit_t *circ, } /* close the circuit: we won't need it anymore. */ circ->_base.purpose = CIRCUIT_PURPOSE_C_INTRODUCE_ACKED; - circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN); + circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_FINISHED); } else { /* It's a NAK; the introduction point didn't relay our request. */ circ->_base.purpose = CIRCUIT_PURPOSE_C_INTRODUCING; diff --git a/src/or/rendmid.c b/src/or/rendmid.c index e96d608d59..740e5d0315 100644 --- a/src/or/rendmid.c +++ b/src/or/rendmid.c @@ -90,7 +90,7 @@ rend_mid_establish_intro(or_circuit_t *circ, const char *request, while ((c = circuit_get_intro_point(pk_digest))) { log_info(LD_REND, "Replacing old circuit for service %s", safe_str(serviceid)); - circuit_mark_for_close(TO_CIRCUIT(c), END_CIRC_REASON_REQUESTED); + circuit_mark_for_close(TO_CIRCUIT(c), END_CIRC_REASON_FINISHED); /* Now it's marked, and it won't be returned next time. */ } diff --git a/src/or/rendservice.c b/src/or/rendservice.c index 773b25eac9..984bf7e7cd 100644 --- a/src/or/rendservice.c +++ b/src/or/rendservice.c @@ -738,8 +738,7 @@ rend_service_intro_has_opened(origin_circuit_t *circuit) if (!service) { log_warn(LD_REND, "Unrecognized service ID %s on introduction circuit %d.", serviceid, circuit->_base.n_circ_id); - /* XXXX Add a no-such-servicer reason? */ - reason = END_CIRC_REASON_CONNECTFAILED; + reason = END_CIRC_REASON_NOSUCHSERVICE; goto err; }