aboutsummaryrefslogtreecommitdiff
path: root/src/or/circuituse.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/or/circuituse.c')
-rw-r--r--src/or/circuituse.c141
1 files changed, 98 insertions, 43 deletions
diff --git a/src/or/circuituse.c b/src/or/circuituse.c
index c0612039be..8fb70f5853 100644
--- a/src/or/circuituse.c
+++ b/src/or/circuituse.c
@@ -85,10 +85,14 @@ circuit_is_acceptable(const origin_circuit_t *origin_circ,
}
if (purpose == CIRCUIT_PURPOSE_C_GENERAL ||
- purpose == CIRCUIT_PURPOSE_C_REND_JOINED)
+ purpose == CIRCUIT_PURPOSE_C_REND_JOINED) {
if (circ->timestamp_dirty &&
circ->timestamp_dirty+get_options()->MaxCircuitDirtiness <= now)
return 0;
+ }
+
+ if (origin_circ->unusable_for_new_conns)
+ return 0;
/* decide if this circ is suitable for this conn */
@@ -105,6 +109,8 @@ circuit_is_acceptable(const origin_circuit_t *origin_circ,
return 0;
if (purpose == CIRCUIT_PURPOSE_C_GENERAL) {
+ tor_addr_t addr;
+ const int family = tor_addr_parse(&addr, conn->socks_request->address);
if (!exitnode && !build_state->onehop_tunnel) {
log_debug(LD_CIRC,"Not considering circuit with unknown router.");
return 0; /* this circuit is screwed and doesn't know it yet,
@@ -125,9 +131,7 @@ circuit_is_acceptable(const origin_circuit_t *origin_circ,
return 0; /* this is a circuit to somewhere else */
if (tor_digest_is_zero(digest)) {
/* we don't know the digest; have to compare addr:port */
- tor_addr_t addr;
- int r = tor_addr_parse(&addr, conn->socks_request->address);
- if (r < 0 ||
+ if (family < 0 ||
!tor_addr_eq(&build_state->chosen_exit->addr, &addr) ||
build_state->chosen_exit->port != conn->socks_request->port)
return 0;
@@ -139,6 +143,13 @@ circuit_is_acceptable(const origin_circuit_t *origin_circ,
return 0;
}
}
+ if (origin_circ->prepend_policy && family != -1) {
+ int r = compare_tor_addr_to_addr_policy(&addr,
+ conn->socks_request->port,
+ origin_circ->prepend_policy);
+ if (r == ADDR_POLICY_REJECTED)
+ return 0;
+ }
if (exitnode && !connection_ap_can_use_exit(conn, exitnode)) {
/* can't exit from this router */
return 0;
@@ -518,15 +529,25 @@ circuit_expire_building(void)
if (timercmp(&victim->timestamp_began, &cutoff, >))
continue; /* it's still young, leave it alone */
- if (!any_opened_circs) {
+ /* We need to double-check the opened state here because
+ * we don't want to consider opened 1-hop dircon circuits for
+ * deciding when to relax the timeout, but we *do* want to relax
+ * those circuits too if nothing else is opened *and* they still
+ * aren't either. */
+ if (!any_opened_circs && victim->state != CIRCUIT_STATE_OPEN) {
/* It's still young enough that we wouldn't close it, right? */
if (timercmp(&victim->timestamp_began, &close_cutoff, >)) {
if (!TO_ORIGIN_CIRCUIT(victim)->relaxed_timeout) {
int first_hop_succeeded = TO_ORIGIN_CIRCUIT(victim)->cpath->state
== CPATH_STATE_OPEN;
log_info(LD_CIRC,
- "No circuits are opened. Relaxing timeout for "
- "a circuit with channel state %s. %d guards are live.",
+ "No circuits are opened. Relaxing timeout for circuit %d "
+ "(a %s %d-hop circuit in state %s with channel state %s). "
+ "%d guards are live.",
+ TO_ORIGIN_CIRCUIT(victim)->global_identifier,
+ circuit_purpose_to_string(victim->purpose),
+ TO_ORIGIN_CIRCUIT(victim)->build_state->desired_path_len,
+ circuit_state_to_string(victim->state),
channel_state_to_string(victim->n_chan->state),
num_live_entry_guards(0));
@@ -541,10 +562,14 @@ circuit_expire_building(void)
} else {
static ratelim_t relax_timeout_limit = RATELIM_INIT(3600);
log_fn_ratelim(&relax_timeout_limit, LOG_NOTICE, LD_CIRC,
- "No circuits are opened. Relaxed timeout for "
- "a circuit with channel state %s to %ldms. "
- "However, it appears the circuit has timed out anyway. "
- "%d guards are live.",
+ "No circuits are opened. Relaxed timeout for circuit %d "
+ "(a %s %d-hop circuit in state %s with channel state %s) to "
+ "%ldms. However, it appears the circuit has timed out "
+ "anyway. %d guards are live.",
+ TO_ORIGIN_CIRCUIT(victim)->global_identifier,
+ circuit_purpose_to_string(victim->purpose),
+ TO_ORIGIN_CIRCUIT(victim)->build_state->desired_path_len,
+ circuit_state_to_string(victim->state),
channel_state_to_string(victim->n_chan->state),
(long)circ_times.close_ms, num_live_entry_guards(0));
}
@@ -660,7 +685,7 @@ circuit_expire_building(void)
circuit_purpose_to_string(victim->purpose));
} else if (circuit_build_times_count_close(&circ_times,
first_hop_succeeded,
- victim->timestamp_began.tv_sec)) {
+ victim->timestamp_created.tv_sec)) {
circuit_build_times_set_timeout(&circ_times);
}
}
@@ -695,9 +720,9 @@ circuit_expire_building(void)
case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT:
case CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED:
/* If we have reached this line, we want to spare the circ for now. */
- log_info(LD_CIRC,"Marking circ %d (state %d:%s, purpose %d) "
+ log_info(LD_CIRC,"Marking circ %u (state %d:%s, purpose %d) "
"as timed-out HS circ",
- victim->n_circ_id,
+ (unsigned)victim->n_circ_id,
victim->state, circuit_state_to_string(victim->state),
victim->purpose);
TO_ORIGIN_CIRCUIT(victim)->hs_circ_has_timed_out = 1;
@@ -713,9 +738,9 @@ circuit_expire_building(void)
if (!(options->CloseHSServiceRendCircuitsImmediatelyOnTimeout) &&
!(TO_ORIGIN_CIRCUIT(victim)->hs_circ_has_timed_out) &&
victim->purpose == CIRCUIT_PURPOSE_S_CONNECT_REND) {
- log_info(LD_CIRC,"Marking circ %d (state %d:%s, purpose %d) "
+ log_info(LD_CIRC,"Marking circ %u (state %d:%s, purpose %d) "
"as timed-out HS circ; relaunching rendezvous attempt.",
- victim->n_circ_id,
+ (unsigned)victim->n_circ_id,
victim->state, circuit_state_to_string(victim->state),
victim->purpose);
TO_ORIGIN_CIRCUIT(victim)->hs_circ_has_timed_out = 1;
@@ -728,7 +753,7 @@ circuit_expire_building(void)
"Abandoning circ %u %s:%d (state %d,%d:%s, purpose %d, "
"len %d)", TO_ORIGIN_CIRCUIT(victim)->global_identifier,
channel_get_canonical_remote_descr(victim->n_chan),
- victim->n_circ_id,
+ (unsigned)victim->n_circ_id,
TO_ORIGIN_CIRCUIT(victim)->has_opened,
victim->state, circuit_state_to_string(victim->state),
victim->purpose,
@@ -737,7 +762,8 @@ circuit_expire_building(void)
log_info(LD_CIRC,
"Abandoning circ %u %d (state %d,%d:%s, purpose %d, len %d)",
TO_ORIGIN_CIRCUIT(victim)->global_identifier,
- victim->n_circ_id, TO_ORIGIN_CIRCUIT(victim)->has_opened,
+ (unsigned)victim->n_circ_id,
+ TO_ORIGIN_CIRCUIT(victim)->has_opened,
victim->state,
circuit_state_to_string(victim->state), victim->purpose,
TO_ORIGIN_CIRCUIT(victim)->build_state->desired_path_len);
@@ -798,9 +824,12 @@ circuit_stream_is_being_handled(entry_connection_t *conn,
circ->purpose == CIRCUIT_PURPOSE_C_GENERAL &&
(!circ->timestamp_dirty ||
circ->timestamp_dirty + get_options()->MaxCircuitDirtiness > now)) {
- cpath_build_state_t *build_state = TO_ORIGIN_CIRCUIT(circ)->build_state;
+ origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ);
+ cpath_build_state_t *build_state = origin_circ->build_state;
if (build_state->is_internal || build_state->onehop_tunnel)
continue;
+ if (!origin_circ->unusable_for_new_conns)
+ continue;
exitnode = build_state_get_exit_node(build_state);
if (exitnode && (!need_uptime || build_state->need_uptime)) {
@@ -842,6 +871,7 @@ circuit_predict_and_launch_new(void)
/* First, count how many of each type of circuit we have already. */
for (circ=global_circuitlist;circ;circ = circ->next) {
cpath_build_state_t *build_state;
+ origin_circuit_t *origin_circ;
if (!CIRCUIT_IS_ORIGIN(circ))
continue;
if (circ->marked_for_close)
@@ -850,7 +880,10 @@ circuit_predict_and_launch_new(void)
continue; /* only count clean circs */
if (circ->purpose != CIRCUIT_PURPOSE_C_GENERAL)
continue; /* only pay attention to general-purpose circs */
- build_state = TO_ORIGIN_CIRCUIT(circ)->build_state;
+ origin_circ = TO_ORIGIN_CIRCUIT(circ);
+ if (origin_circ->unusable_for_new_conns)
+ continue;
+ build_state = origin_circ->build_state;
if (build_state->onehop_tunnel)
continue;
num++;
@@ -1070,9 +1103,10 @@ circuit_expire_old_circuits_clientside(void)
circ->timestamp_dirty + get_options()->MaxCircuitDirtiness <
now.tv_sec &&
!TO_ORIGIN_CIRCUIT(circ)->p_streams /* nothing attached */ ) {
- log_debug(LD_CIRC, "Closing n_circ_id %d (dirty %ld sec ago, "
+ log_debug(LD_CIRC, "Closing n_circ_id %u (dirty %ld sec ago, "
"purpose %d)",
- circ->n_circ_id, (long)(now.tv_sec - circ->timestamp_dirty),
+ (unsigned)circ->n_circ_id,
+ (long)(now.tv_sec - circ->timestamp_dirty),
circ->purpose);
/* Don't do this magic for testing circuits. Their death is governed
* by circuit_expire_building */
@@ -1153,8 +1187,8 @@ circuit_expire_old_circuits_serverside(time_t now)
!or_circ->n_streams && !or_circ->resolving_streams &&
or_circ->p_chan &&
channel_when_last_xmit(or_circ->p_chan) <= cutoff) {
- log_info(LD_CIRC, "Closing circ_id %d (empty %d secs ago)",
- or_circ->p_circ_id,
+ log_info(LD_CIRC, "Closing circ_id %u (empty %d secs ago)",
+ (unsigned)or_circ->p_circ_id,
(int)(now - channel_when_last_xmit(or_circ->p_chan)));
circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED);
}
@@ -1896,8 +1930,8 @@ link_apconn_to_circ(entry_connection_t *apconn, origin_circuit_t *circ,
const node_t *exitnode;
/* add it into the linked list of streams on this circuit */
- log_debug(LD_APP|LD_CIRC, "attaching new conn to circ. n_circ_id %d.",
- circ->base_.n_circ_id);
+ log_debug(LD_APP|LD_CIRC, "attaching new conn to circ. n_circ_id %u.",
+ (unsigned)circ->base_.n_circ_id);
/* reset it, so we can measure circ timeouts */
ENTRY_TO_CONN(apconn)->timestamp_lastread = time(NULL);
ENTRY_TO_EDGE_CONN(apconn)->next_stream = circ->p_streams;
@@ -2121,8 +2155,8 @@ connection_ap_handshake_attach_circuit(entry_connection_t *conn)
return retval;
log_debug(LD_APP|LD_CIRC,
- "Attaching apconn to circ %d (stream %d sec old).",
- circ->base_.n_circ_id, conn_age);
+ "Attaching apconn to circ %u (stream %d sec old).",
+ (unsigned)circ->base_.n_circ_id, conn_age);
/* print the circ's path, so people can figure out which circs are
* sucking. */
circuit_log_path(LOG_INFO,LD_APP|LD_CIRC,circ);
@@ -2147,7 +2181,7 @@ connection_ap_handshake_attach_circuit(entry_connection_t *conn)
log_info(LD_REND,
"rend joined circ %d already here. attaching. "
"(stream %d sec old)",
- rendcirc->base_.n_circ_id, conn_age);
+ (unsigned)rendcirc->base_.n_circ_id, conn_age);
/* Mark rendezvous circuits as 'newly dirty' every time you use
* them, since the process of rebuilding a rendezvous circ is so
* expensive. There is a tradeoff between linkability and
@@ -2168,9 +2202,9 @@ connection_ap_handshake_attach_circuit(entry_connection_t *conn)
if (rendcirc && (rendcirc->base_.purpose ==
CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED)) {
log_info(LD_REND,
- "pending-join circ %d already here, with intro ack. "
+ "pending-join circ %u already here, with intro ack. "
"Stalling. (stream %d sec old)",
- rendcirc->base_.n_circ_id, conn_age);
+ (unsigned)rendcirc->base_.n_circ_id, conn_age);
return 0;
}
@@ -2182,10 +2216,10 @@ connection_ap_handshake_attach_circuit(entry_connection_t *conn)
if (retval > 0) {
/* one has already sent the intro. keep waiting. */
tor_assert(introcirc);
- log_info(LD_REND, "Intro circ %d present and awaiting ack (rend %d). "
+ log_info(LD_REND, "Intro circ %u present and awaiting ack (rend %u). "
"Stalling. (stream %d sec old)",
- introcirc->base_.n_circ_id,
- rendcirc ? rendcirc->base_.n_circ_id : 0,
+ (unsigned)introcirc->base_.n_circ_id,
+ rendcirc ? (unsigned)rendcirc->base_.n_circ_id : 0,
conn_age);
return 0;
}
@@ -2195,16 +2229,17 @@ connection_ap_handshake_attach_circuit(entry_connection_t *conn)
if (rendcirc && introcirc &&
rendcirc->base_.purpose == CIRCUIT_PURPOSE_C_REND_READY) {
log_info(LD_REND,
- "ready rend circ %d already here (no intro-ack yet on "
- "intro %d). (stream %d sec old)",
- rendcirc->base_.n_circ_id,
- introcirc->base_.n_circ_id, conn_age);
+ "ready rend circ %u already here (no intro-ack yet on "
+ "intro %u). (stream %d sec old)",
+ (unsigned)rendcirc->base_.n_circ_id,
+ (unsigned)introcirc->base_.n_circ_id, conn_age);
tor_assert(introcirc->base_.purpose == CIRCUIT_PURPOSE_C_INTRODUCING);
if (introcirc->base_.state == CIRCUIT_STATE_OPEN) {
- log_info(LD_REND,"found open intro circ %d (rend %d); sending "
+ log_info(LD_REND,"found open intro circ %u (rend %u); sending "
"introduction. (stream %d sec old)",
- introcirc->base_.n_circ_id, rendcirc->base_.n_circ_id,
+ (unsigned)introcirc->base_.n_circ_id,
+ (unsigned)rendcirc->base_.n_circ_id,
conn_age);
switch (rend_client_send_introduction(introcirc, rendcirc)) {
case 0: /* success */
@@ -2228,10 +2263,10 @@ connection_ap_handshake_attach_circuit(entry_connection_t *conn)
}
}
- log_info(LD_REND, "Intro (%d) and rend (%d) circs are not both ready. "
+ log_info(LD_REND, "Intro (%u) and rend (%u) circs are not both ready. "
"Stalling conn. (%d sec old)",
- introcirc ? introcirc->base_.n_circ_id : 0,
- rendcirc ? rendcirc->base_.n_circ_id : 0, conn_age);
+ introcirc ? (unsigned)introcirc->base_.n_circ_id : 0,
+ rendcirc ? (unsigned)rendcirc->base_.n_circ_id : 0, conn_age);
return 0;
}
}
@@ -2272,3 +2307,23 @@ circuit_change_purpose(circuit_t *circ, uint8_t new_purpose)
}
}
+/** Mark <b>circ</b> so that no more connections can be attached to it. */
+void
+mark_circuit_unusable_for_new_conns(origin_circuit_t *circ)
+{
+ const or_options_t *options = get_options();
+ tor_assert(circ);
+
+ /* XXXX025 This is a kludge; we're only keeping it around in case there's
+ * something that doesn't check unusable_for_new_conns, and to avoid
+ * deeper refactoring of our expiration logic. */
+ if (! circ->base_.timestamp_dirty)
+ circ->base_.timestamp_dirty = approx_time();
+ if (options->MaxCircuitDirtiness >= circ->base_.timestamp_dirty)
+ circ->base_.timestamp_dirty = 1; /* prevent underflow */
+ else
+ circ->base_.timestamp_dirty -= options->MaxCircuitDirtiness;
+
+ circ->unusable_for_new_conns = 1;
+}
+