static int count_acceptable_nodes(smartlist_t *routers);
static int onion_append_hop(crypt_path_t **head_ptr, extend_info_t *choice);
static int entry_guard_inc_first_hop_count(entry_guard_t *guard);
-static void pathbias_count_success(origin_circuit_t *circ);
+static void pathbias_count_build_success(origin_circuit_t *circ);
+static void pathbias_count_successful_close(origin_circuit_t *circ);
+static void pathbias_count_collapse(origin_circuit_t *circ);
+static void pathbias_count_unusable(origin_circuit_t *circ);
/** This function tries to get a channel to the specified endpoint,
* and then calls command_setup_channel() to give it the right
}
}
- pathbias_count_success(circ);
+ pathbias_count_build_success(circ);
circuit_rep_hist_note_result(circ);
circuit_has_opened(circ); /* do other actions as necessary */
return "new";
case PATH_STATE_DID_FIRST_HOP:
return "first hop";
- case PATH_STATE_SUCCEEDED:
- return "succeeded";
+ case PATH_STATE_BUILD_SUCCEEDED:
+ return "build succeeded";
+ case PATH_STATE_USE_SUCCEEDED:
+ return "use succeeded";
}
return "unknown";
}
}
- /* Don't count cannibalized circs for path bias */
+ /* Don't re-count cannibalized circs.. */
if (!circ->has_opened) {
entry_guard_t *guard = NULL;
* Also check for several potential error cases for bug #6475.
*/
static void
-pathbias_count_success(origin_circuit_t *circ)
+pathbias_count_build_success(origin_circuit_t *circ)
{
#define SUCCESS_NOTICE_INTERVAL (600)
static ratelim_t success_notice_limit =
return;
}
- /* Don't count cannibalized/reused circs for path bias */
+ /* Don't count cannibalized/reused circs for path bias
+ * build success.. They get counted under use success */
if (!circ->has_opened) {
if (circ->cpath && circ->cpath->extend_info) {
guard = entry_guard_get_by_id_digest(
if (guard) {
if (circ->path_state == PATH_STATE_DID_FIRST_HOP) {
- circ->path_state = PATH_STATE_SUCCEEDED;
+ circ->path_state = PATH_STATE_BUILD_SUCCEEDED;
guard->circuit_successes++;
log_info(LD_CIRC, "Got success count %u/%u for guard %s=%s",
}
}
} else {
- if (circ->path_state != PATH_STATE_SUCCEEDED) {
+ if (circ->path_state < PATH_STATE_BUILD_SUCCEEDED) {
if ((rate_msg = rate_limit_log(&success_notice_limit,
approx_time()))) {
log_info(LD_BUG,
}
/**
- * Count a successfully closed circuit.
+ * Check if a circuit was used and/or closed successfully.
*/
void
+pathbias_check_close(origin_circuit_t *ocirc, int reason)
+{
+ circuit_t *circ = ô->base_;
+
+ if (ocirc->path_state == PATH_STATE_BUILD_SUCCEEDED) {
+ if (circ->timestamp_dirty) {
+ // XXX: May open up attacks if the adversary can force connections
+ // on unresponsive hosts to use new circs. Vidalia displayes a "Retrying"
+ // state.. Can we use that? Does optimistic data change this?
+ // XXX: For the hidserv side, we could only care about INTRODUCING purposes
+ // for server+client, and REND purposes for the server... Can we
+ // somehow only count those?
+ /* Any circuit where there were attempted streams but no successful
+ * streams could be bias */
+ log_info(LD_CIRC,
+ "Circuit closed without successful use for reason %d. "
+ "Circuit is a %s currently %s.",
+ reason, circuit_purpose_to_string(circ->purpose),
+ circuit_state_to_string(circ->state));
+ pathbias_count_unusable(ocirc);
+ } else {
+ if (reason & END_CIRC_REASON_FLAG_REMOTE) {
+ /* Unused remote circ close reasons all could be bias */
+ // XXX: We hit this a lot for hidserv circs with purposes:
+ // CIRCUIT_PURPOSE_S_CONNECT_REND (reasons: 514,517,520)
+ // CIRCUIT_PURPOSE_S_REND_JOINED (reasons: 514,517,520)
+ // == reasons: 2,3,8. Client-side timeouts?
+ log_info(LD_CIRC,
+ "Circuit remote-closed without successful use for reason %d. "
+ "Circuit is a %s currently %s.",
+ reason, circuit_purpose_to_string(circ->purpose),
+ circuit_state_to_string(circ->state));
+ pathbias_count_collapse(ocirc);
+ } else if ((reason & ~END_CIRC_REASON_FLAG_REMOTE)
+ == END_CIRC_REASON_CHANNEL_CLOSED &&
+ circ->n_chan &&
+ circ->n_chan->reason_for_closing
+ != CHANNEL_CLOSE_REQUESTED) {
+ /* If we didn't close the channel ourselves, it could be bias */
+ /* FIXME: Only count bias if the network is live?
+ * What about clock jumps/suspends? */
+ log_info(LD_CIRC,
+ "Circuit's channel closed without successful use for reason %d, "
+ "channel reason %d. Circuit is a %s currently %s.",
+ reason, circ->n_chan->reason_for_closing,
+ circuit_purpose_to_string(circ->purpose),
+ circuit_state_to_string(circ->state));
+ pathbias_count_collapse(ocirc);
+ } else {
+ pathbias_count_successful_close(ocirc);
+ }
+ }
+ } else if (ocirc->path_state == PATH_STATE_USE_SUCCEEDED) {
+ pathbias_count_successful_close(ocirc);
+ }
+}
+
+/**
+ * Count a successfully closed circuit.
+ */
+static void
pathbias_count_successful_close(origin_circuit_t *circ)
{
entry_guard_t *guard = NULL;
* circuit after it has successfully completed. Right now, this is
* used for purely informational/debugging purposes.
*/
-void
+static void
pathbias_count_collapse(origin_circuit_t *circ)
{
entry_guard_t *guard = NULL;
}
}
-void
+static void
pathbias_count_unusable(origin_circuit_t *circ)
{
entry_guard_t *guard = NULL;
if(!ocirc->cpath || !ocirc->cpath->extend_info)
continue;
- if (ocirc->path_state == PATH_STATE_SUCCEEDED &&
+ if (ocirc->path_state >= PATH_STATE_BUILD_SUCCEEDED &&
(memcmp(guard->identity,
ocirc->cpath->extend_info->identity_digest,
DIGEST_LEN)
circuit_mark_for_close(TO_CIRCUIT(circ), -err_reason);
return -1;
}
+
+ /* Set timestamp_dirty, so we can check it for path use bias */
+ if (!circ->base_.timestamp_dirty)
+ circ->base_.timestamp_dirty = time(NULL);
+
return 0;
}
}
if (CIRCUIT_IS_ORIGIN(circ)) {
- origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
-
- if (ocirc->path_state == PATH_STATE_SUCCEEDED) {
- int pathbias_is_normal_close = 1;
-
- /* FIXME: Is timestamp_dirty the right thing for these two checks?
- * Should we use isolation_any_streams_attached instead?
- * isolation_any_streams_attached is not used for hidservs.. */
- if (!circ->timestamp_dirty) {
- if (orig_reason & END_CIRC_REASON_FLAG_REMOTE) {
- /* Unused remote circ close reasons all could be bias */
- // XXX: We hit this a lot for hidserv circs with purposes:
- // CIRCUIT_PURPOSE_S_CONNECT_REND (reasons: 514,517,520)
- // CIRCUIT_PURPOSE_S_REND_JOINED (reasons: 514,517,520)
- // == reasons: 2,3,8. Client-side timeouts?
- pathbias_is_normal_close = 0;
- pathbias_count_collapse(ocirc);
- } else if ((reason & ~END_CIRC_REASON_FLAG_REMOTE)
- == END_CIRC_REASON_CHANNEL_CLOSED &&
- circ->n_chan &&
- circ->n_chan->reason_for_closing
- != CHANNEL_CLOSE_REQUESTED) {
- /* If we didn't close the channel ourselves, it could be bias */
- /* FIXME: Only count bias if the network is live?
- * What about clock jumps/suspends? */
- pathbias_is_normal_close = 0;
- pathbias_count_collapse(ocirc);
- }
- } else if (circ->timestamp_dirty && !ocirc->any_streams_succeeded) {
- // XXX: May open up attacks if the adversary can force connections
- // on unresponsive hosts to use new circs. Vidalia displayes a "Retrying"
- // state.. Can we use that? Does optimistic data change this?
- // XXX: For the hidserv side, we could only care about INTRODUCING purposes
- // for server+client, and REND purposes for the server... Can we
- // somehow only count those?
- /* Any circuit where there were attempted streams but no successful
- * streams could be bias */
- /* FIXME: This may be better handled by limiting the number of retries
- * per stream? */
- pathbias_is_normal_close = 0;
- pathbias_count_unusable(ocirc);
- }
-
- if (pathbias_is_normal_close) {
- pathbias_count_successful_close(ocirc);
- }
- }
+ pathbias_check_close(TO_ORIGIN_CIRCUIT(circ), reason);
/* We don't send reasons when closing circuits at the origin. */
reason = END_CIRC_REASON_NONE;
/** This circuit has completed a first hop, and has been counted by
* the path bias logic. */
PATH_STATE_DID_FIRST_HOP = 1,
- /** This circuit has been completely built, and has been counted as
- * successful by the path bias logic. */
- PATH_STATE_SUCCEEDED = 2,
+ /** This circuit has been completely built */
+ PATH_STATE_BUILD_SUCCEEDED = 2,
+ /** Did any SOCKS streams or hidserv introductions actually succeed on
+ * this circuit?
+ *
+ * Note: If we ever implement end-to-end stream timing through test
+ * stream probes (#5707), we must *not* set this for those probes
+ * (or any other automatic streams) because the adversary could
+ * just tag at a later point.
+ */
+ PATH_STATE_USE_SUCCEEDED = 3,
} path_state_t;
/** An origin_circuit_t holds data necessary to build and use a circuit.
*/
unsigned int isolation_any_streams_attached : 1;
- /**
- * Did any SOCKS streams or hidserv introductions actually succeed on
- * this circuit?
- *
- * Note: If we ever implement end-to-end stream timing through test
- * stream probes (#5707), we must *not* set this for those probes
- * (or any other automatic streams).
- */
- unsigned int any_streams_succeeded : 1;
-
/** A bitfield of ISO_* flags for every isolation field such that this
* circuit has had streams with more than one value for that field
* attached to it. */