|
@@ -54,6 +54,7 @@
|
|
#include "rephist.h"
|
|
#include "rephist.h"
|
|
#include "router.h"
|
|
#include "router.h"
|
|
#include "routerlist.h"
|
|
#include "routerlist.h"
|
|
|
|
+#include "config.h"
|
|
|
|
|
|
static void circuit_expire_old_circuits_clientside(void);
|
|
static void circuit_expire_old_circuits_clientside(void);
|
|
static void circuit_increment_failure_count(void);
|
|
static void circuit_increment_failure_count(void);
|
|
@@ -133,6 +134,7 @@ circuit_is_acceptable(const origin_circuit_t *origin_circ,
|
|
}
|
|
}
|
|
|
|
|
|
if (purpose == CIRCUIT_PURPOSE_C_GENERAL ||
|
|
if (purpose == CIRCUIT_PURPOSE_C_GENERAL ||
|
|
|
|
+ purpose == CIRCUIT_PURPOSE_HS_VANGUARDS ||
|
|
purpose == CIRCUIT_PURPOSE_C_REND_JOINED) {
|
|
purpose == CIRCUIT_PURPOSE_C_REND_JOINED) {
|
|
if (circ->timestamp_dirty &&
|
|
if (circ->timestamp_dirty &&
|
|
circ->timestamp_dirty+get_options()->MaxCircuitDirtiness <= now)
|
|
circ->timestamp_dirty+get_options()->MaxCircuitDirtiness <= now)
|
|
@@ -156,7 +158,9 @@ circuit_is_acceptable(const origin_circuit_t *origin_circ,
|
|
if (need_internal != build_state->is_internal)
|
|
if (need_internal != build_state->is_internal)
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
- if (purpose == CIRCUIT_PURPOSE_C_GENERAL) {
|
|
|
|
|
|
+ if (purpose == CIRCUIT_PURPOSE_C_GENERAL ||
|
|
|
|
+ purpose == CIRCUIT_PURPOSE_S_HSDIR_POST ||
|
|
|
|
+ purpose == CIRCUIT_PURPOSE_C_HSDIR_GET) {
|
|
tor_addr_t addr;
|
|
tor_addr_t addr;
|
|
const int family = tor_addr_parse(&addr, conn->socks_request->address);
|
|
const int family = tor_addr_parse(&addr, conn->socks_request->address);
|
|
if (!exitnode && !build_state->onehop_tunnel) {
|
|
if (!exitnode && !build_state->onehop_tunnel) {
|
|
@@ -238,6 +242,8 @@ circuit_is_better(const origin_circuit_t *oa, const origin_circuit_t *ob,
|
|
return 1; /* oa is better. It's not relaxed. */
|
|
return 1; /* oa is better. It's not relaxed. */
|
|
|
|
|
|
switch (purpose) {
|
|
switch (purpose) {
|
|
|
|
+ case CIRCUIT_PURPOSE_S_HSDIR_POST:
|
|
|
|
+ case CIRCUIT_PURPOSE_C_HSDIR_GET:
|
|
case CIRCUIT_PURPOSE_C_GENERAL:
|
|
case CIRCUIT_PURPOSE_C_GENERAL:
|
|
/* if it's used but less dirty it's best;
|
|
/* if it's used but less dirty it's best;
|
|
* else if it's more recently created it's best
|
|
* else if it's more recently created it's best
|
|
@@ -323,6 +329,9 @@ circuit_get_best(const entry_connection_t *conn,
|
|
tor_assert(conn);
|
|
tor_assert(conn);
|
|
|
|
|
|
tor_assert(purpose == CIRCUIT_PURPOSE_C_GENERAL ||
|
|
tor_assert(purpose == CIRCUIT_PURPOSE_C_GENERAL ||
|
|
|
|
+ purpose == CIRCUIT_PURPOSE_HS_VANGUARDS ||
|
|
|
|
+ purpose == CIRCUIT_PURPOSE_C_HSDIR_GET ||
|
|
|
|
+ purpose == CIRCUIT_PURPOSE_S_HSDIR_POST ||
|
|
purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT ||
|
|
purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT ||
|
|
purpose == CIRCUIT_PURPOSE_C_REND_JOINED);
|
|
purpose == CIRCUIT_PURPOSE_C_REND_JOINED);
|
|
|
|
|
|
@@ -1080,7 +1089,8 @@ circuit_is_available_for_use(const circuit_t *circ)
|
|
return 0; /* Don't mess with marked circs */
|
|
return 0; /* Don't mess with marked circs */
|
|
if (circ->timestamp_dirty)
|
|
if (circ->timestamp_dirty)
|
|
return 0; /* Only count clean circs */
|
|
return 0; /* Only count clean circs */
|
|
- if (circ->purpose != CIRCUIT_PURPOSE_C_GENERAL)
|
|
|
|
|
|
+ if (circ->purpose != CIRCUIT_PURPOSE_C_GENERAL &&
|
|
|
|
+ circ->purpose != CIRCUIT_PURPOSE_HS_VANGUARDS)
|
|
return 0; /* We only pay attention to general purpose circuits.
|
|
return 0; /* We only pay attention to general purpose circuits.
|
|
General purpose circuits are always origin circuits. */
|
|
General purpose circuits are always origin circuits. */
|
|
|
|
|
|
@@ -1192,6 +1202,25 @@ needs_circuits_for_build(int num)
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * Launch the appropriate type of predicted circuit for hidden
|
|
|
|
+ * services, depending on our options.
|
|
|
|
+ */
|
|
|
|
+static void
|
|
|
|
+circuit_launch_predicted_hs_circ(int flags)
|
|
|
|
+{
|
|
|
|
+ /* K.I.S.S. implementation of bug #23101: If we are using
|
|
|
|
+ * vanguards or pinned middles, pre-build a specific purpose
|
|
|
|
+ * for HS circs. */
|
|
|
|
+ if (circuit_should_use_vanguards(CIRCUIT_PURPOSE_HS_VANGUARDS)) {
|
|
|
|
+ circuit_launch(CIRCUIT_PURPOSE_HS_VANGUARDS, flags);
|
|
|
|
+ } else {
|
|
|
|
+ /* If no vanguards, then no HS-specific prebuilt circuits are needed.
|
|
|
|
+ * Normal GENERAL circs are fine */
|
|
|
|
+ circuit_launch(CIRCUIT_PURPOSE_C_GENERAL, flags);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
/** Determine how many circuits we have open that are clean,
|
|
/** Determine how many circuits we have open that are clean,
|
|
* Make sure it's enough for all the upcoming behaviors we predict we'll have.
|
|
* Make sure it's enough for all the upcoming behaviors we predict we'll have.
|
|
* But put an upper bound on the total number of circuits.
|
|
* But put an upper bound on the total number of circuits.
|
|
@@ -1245,7 +1274,7 @@ circuit_predict_and_launch_new(void)
|
|
"Have %d clean circs (%d internal), need another internal "
|
|
"Have %d clean circs (%d internal), need another internal "
|
|
"circ for my hidden service.",
|
|
"circ for my hidden service.",
|
|
num, num_internal);
|
|
num, num_internal);
|
|
- circuit_launch(CIRCUIT_PURPOSE_C_GENERAL, flags);
|
|
|
|
|
|
+ circuit_launch_predicted_hs_circ(flags);
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1263,7 +1292,8 @@ circuit_predict_and_launch_new(void)
|
|
"Have %d clean circs (%d uptime-internal, %d internal), need"
|
|
"Have %d clean circs (%d uptime-internal, %d internal), need"
|
|
" another hidden service circ.",
|
|
" another hidden service circ.",
|
|
num, num_uptime_internal, num_internal);
|
|
num, num_uptime_internal, num_internal);
|
|
- circuit_launch(CIRCUIT_PURPOSE_C_GENERAL, flags);
|
|
|
|
|
|
+
|
|
|
|
+ circuit_launch_predicted_hs_circ(flags);
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1458,6 +1488,9 @@ circuit_expire_old_circuits_clientside(void)
|
|
} else if (!circ->timestamp_dirty && circ->state == CIRCUIT_STATE_OPEN) {
|
|
} else if (!circ->timestamp_dirty && circ->state == CIRCUIT_STATE_OPEN) {
|
|
if (timercmp(&circ->timestamp_began, &cutoff, OP_LT)) {
|
|
if (timercmp(&circ->timestamp_began, &cutoff, OP_LT)) {
|
|
if (circ->purpose == CIRCUIT_PURPOSE_C_GENERAL ||
|
|
if (circ->purpose == CIRCUIT_PURPOSE_C_GENERAL ||
|
|
|
|
+ circ->purpose == CIRCUIT_PURPOSE_C_HSDIR_GET ||
|
|
|
|
+ circ->purpose == CIRCUIT_PURPOSE_S_HSDIR_POST ||
|
|
|
|
+ circ->purpose == CIRCUIT_PURPOSE_HS_VANGUARDS ||
|
|
circ->purpose == CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT ||
|
|
circ->purpose == CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT ||
|
|
circ->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO ||
|
|
circ->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO ||
|
|
circ->purpose == CIRCUIT_PURPOSE_TESTING ||
|
|
circ->purpose == CIRCUIT_PURPOSE_TESTING ||
|
|
@@ -1650,6 +1683,8 @@ circuit_has_opened(origin_circuit_t *circ)
|
|
hs_client_circuit_has_opened(circ);
|
|
hs_client_circuit_has_opened(circ);
|
|
break;
|
|
break;
|
|
case CIRCUIT_PURPOSE_C_GENERAL:
|
|
case CIRCUIT_PURPOSE_C_GENERAL:
|
|
|
|
+ case CIRCUIT_PURPOSE_C_HSDIR_GET:
|
|
|
|
+ case CIRCUIT_PURPOSE_S_HSDIR_POST:
|
|
/* Tell any AP connections that have been waiting for a new
|
|
/* Tell any AP connections that have been waiting for a new
|
|
* circuit that one is ready. */
|
|
* circuit that one is ready. */
|
|
circuit_try_attaching_streams(circ);
|
|
circuit_try_attaching_streams(circ);
|
|
@@ -1727,6 +1762,8 @@ circuit_build_failed(origin_circuit_t *circ)
|
|
circ->cpath->prev->prev->state == CPATH_STATE_OPEN) {
|
|
circ->cpath->prev->prev->state == CPATH_STATE_OPEN) {
|
|
failed_at_last_hop = 1;
|
|
failed_at_last_hop = 1;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ /* Check if we failed at first hop */
|
|
if (circ->cpath &&
|
|
if (circ->cpath &&
|
|
circ->cpath->state != CPATH_STATE_OPEN &&
|
|
circ->cpath->state != CPATH_STATE_OPEN &&
|
|
! circ->base_.received_destroy) {
|
|
! circ->base_.received_destroy) {
|
|
@@ -1762,8 +1799,22 @@ circuit_build_failed(origin_circuit_t *circ)
|
|
TO_CIRCUIT(circ)->n_circ_id, circ->global_identifier);
|
|
TO_CIRCUIT(circ)->n_circ_id, circ->global_identifier);
|
|
}
|
|
}
|
|
if (n_chan_id && !already_marked) {
|
|
if (n_chan_id && !already_marked) {
|
|
- /* New guard API: we failed. */
|
|
|
|
- if (circ->guard_state)
|
|
|
|
|
|
+ /*
|
|
|
|
+ * If we have guard state (new guard API) and our path selection
|
|
|
|
+ * code actually chose a full path, then blame the failure of this
|
|
|
|
+ * circuit on the guard.
|
|
|
|
+ *
|
|
|
|
+ * Note that we deliberately use circuit_get_cpath_len() (and not
|
|
|
|
+ * circuit_get_cpath_opened_len()) because we only want to ensure
|
|
|
|
+ * that a full path is *chosen*. This is different than a full path
|
|
|
|
+ * being *built*. We only want to blame *build* failures on this
|
|
|
|
+ * guard. Path selection failures can happen spuriously for a number
|
|
|
|
+ * of reasons (such as aggressive/invalid user-specified path
|
|
|
|
+ * restrictions in the torrc, as well as non-user reasons like
|
|
|
|
+ * exitpolicy issues), and so should not be counted here.
|
|
|
|
+ */
|
|
|
|
+ if (circ->guard_state &&
|
|
|
|
+ circuit_get_cpath_len(circ) >= circ->build_state->desired_path_len)
|
|
entry_guard_failed(&circ->guard_state);
|
|
entry_guard_failed(&circ->guard_state);
|
|
/* if there are any one-hop streams waiting on this circuit, fail
|
|
/* if there are any one-hop streams waiting on this circuit, fail
|
|
* them now so they can retry elsewhere. */
|
|
* them now so they can retry elsewhere. */
|
|
@@ -1772,6 +1823,8 @@ circuit_build_failed(origin_circuit_t *circ)
|
|
}
|
|
}
|
|
|
|
|
|
switch (circ->base_.purpose) {
|
|
switch (circ->base_.purpose) {
|
|
|
|
+ case CIRCUIT_PURPOSE_C_HSDIR_GET:
|
|
|
|
+ case CIRCUIT_PURPOSE_S_HSDIR_POST:
|
|
case CIRCUIT_PURPOSE_C_GENERAL:
|
|
case CIRCUIT_PURPOSE_C_GENERAL:
|
|
/* If we never built the circuit, note it as a failure. */
|
|
/* If we never built the circuit, note it as a failure. */
|
|
circuit_increment_failure_count();
|
|
circuit_increment_failure_count();
|
|
@@ -1856,6 +1909,106 @@ have_enough_path_info(int need_exit)
|
|
return router_have_consensus_path() != CONSENSUS_PATH_UNKNOWN;
|
|
return router_have_consensus_path() != CONSENSUS_PATH_UNKNOWN;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * Tell us if a circuit is a hidden service circuit.
|
|
|
|
+ */
|
|
|
|
+int
|
|
|
|
+circuit_purpose_is_hidden_service(uint8_t purpose)
|
|
|
|
+{
|
|
|
|
+ if (purpose == CIRCUIT_PURPOSE_HS_VANGUARDS) {
|
|
|
|
+ return 1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Client-side purpose */
|
|
|
|
+ if (purpose >= CIRCUIT_PURPOSE_C_HS_MIN_ &&
|
|
|
|
+ purpose <= CIRCUIT_PURPOSE_C_HS_MAX_) {
|
|
|
|
+ return 1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Service-side purpose */
|
|
|
|
+ if (purpose >= CIRCUIT_PURPOSE_S_HS_MIN_ &&
|
|
|
|
+ purpose <= CIRCUIT_PURPOSE_S_HS_MAX_) {
|
|
|
|
+ return 1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * Return true if this circuit purpose should use vanguards
|
|
|
|
+ * or pinned Layer2 or Layer3 guards.
|
|
|
|
+ *
|
|
|
|
+ * This function takes both the circuit purpose and the
|
|
|
|
+ * torrc options for pinned middles/vanguards into account
|
|
|
|
+ * (ie: the circuit must be a hidden service circuit and
|
|
|
|
+ * vanguards/pinned middles must be enabled for it to return
|
|
|
|
+ * true).
|
|
|
|
+ */
|
|
|
|
+int
|
|
|
|
+circuit_should_use_vanguards(uint8_t purpose)
|
|
|
|
+{
|
|
|
|
+ const or_options_t *options = get_options();
|
|
|
|
+
|
|
|
|
+ /* Only hidden service circuits use vanguards */
|
|
|
|
+ if (!circuit_purpose_is_hidden_service(purpose))
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+ /* Pinned middles are effectively vanguards */
|
|
|
|
+ if (options->HSLayer2Nodes || options->HSLayer3Nodes)
|
|
|
|
+ return 1;
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * Return true for the set of conditions for which it is OK to use
|
|
|
|
+ * a cannibalized circuit.
|
|
|
|
+ *
|
|
|
|
+ * Don't cannibalize for onehops, or tor2web, or certain purposes.
|
|
|
|
+ */
|
|
|
|
+static int
|
|
|
|
+circuit_should_cannibalize_to_build(uint8_t purpose_to_build,
|
|
|
|
+ int has_extend_info,
|
|
|
|
+ int onehop_tunnel,
|
|
|
|
+ int need_specific_rp)
|
|
|
|
+{
|
|
|
|
+
|
|
|
|
+ /* Do not try to cannibalize if this is a one hop circuit, or
|
|
|
|
+ * is a tor2web/special rp. */
|
|
|
|
+ if (onehop_tunnel || need_specific_rp) {
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Don't try to cannibalize for general purpose circuits that do not
|
|
|
|
+ * specify a custom exit. */
|
|
|
|
+ if (purpose_to_build == CIRCUIT_PURPOSE_C_GENERAL && !has_extend_info) {
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Don't cannibalize for testing circuits. We want to see if they
|
|
|
|
+ * complete normally. Also don't cannibalize for vanguard-purpose
|
|
|
|
+ * circuits, since those are specially pre-built for later
|
|
|
|
+ * cannibalization by the actual specific circuit types that need
|
|
|
|
+ * vanguards.
|
|
|
|
+ */
|
|
|
|
+ if (purpose_to_build == CIRCUIT_PURPOSE_TESTING ||
|
|
|
|
+ purpose_to_build == CIRCUIT_PURPOSE_HS_VANGUARDS) {
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* For vanguards, the server-side intro circ is not cannibalized
|
|
|
|
+ * because we pre-build 4 hop HS circuits, and it only needs a 3 hop
|
|
|
|
+ * circuit. It is also long-lived, so it is more important that
|
|
|
|
+ * it have lower latency than get built fast.
|
|
|
|
+ */
|
|
|
|
+ if (circuit_should_use_vanguards(purpose_to_build) &&
|
|
|
|
+ purpose_to_build == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO) {
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 1;
|
|
|
|
+}
|
|
|
|
+
|
|
/** Launch a new circuit with purpose <b>purpose</b> and exit node
|
|
/** Launch a new circuit with purpose <b>purpose</b> and exit node
|
|
* <b>extend_info</b> (or NULL to select a random exit node). If flags
|
|
* <b>extend_info</b> (or NULL to select a random exit node). If flags
|
|
* contains CIRCLAUNCH_NEED_UPTIME, choose among routers with high uptime. If
|
|
* contains CIRCLAUNCH_NEED_UPTIME, choose among routers with high uptime. If
|
|
@@ -1890,9 +2043,12 @@ circuit_launch_by_extend_info(uint8_t purpose,
|
|
need_specific_rp = 1;
|
|
need_specific_rp = 1;
|
|
}
|
|
}
|
|
|
|
|
|
- if ((extend_info || purpose != CIRCUIT_PURPOSE_C_GENERAL) &&
|
|
|
|
- purpose != CIRCUIT_PURPOSE_TESTING &&
|
|
|
|
- !onehop_tunnel && !need_specific_rp) {
|
|
|
|
|
|
+ /* If we can/should cannibalize another circuit to build this one,
|
|
|
|
+ * then do so. */
|
|
|
|
+ if (circuit_should_cannibalize_to_build(purpose,
|
|
|
|
+ extend_info != NULL,
|
|
|
|
+ onehop_tunnel,
|
|
|
|
+ need_specific_rp)) {
|
|
/* see if there are appropriate circs available to cannibalize. */
|
|
/* see if there are appropriate circs available to cannibalize. */
|
|
/* XXX if we're planning to add a hop, perhaps we want to look for
|
|
/* XXX if we're planning to add a hop, perhaps we want to look for
|
|
* internal circs rather than exit circs? -RD */
|
|
* internal circs rather than exit circs? -RD */
|
|
@@ -1947,6 +2103,8 @@ circuit_launch_by_extend_info(uint8_t purpose,
|
|
case CIRCUIT_PURPOSE_C_INTRODUCING:
|
|
case CIRCUIT_PURPOSE_C_INTRODUCING:
|
|
case CIRCUIT_PURPOSE_S_CONNECT_REND:
|
|
case CIRCUIT_PURPOSE_S_CONNECT_REND:
|
|
case CIRCUIT_PURPOSE_C_GENERAL:
|
|
case CIRCUIT_PURPOSE_C_GENERAL:
|
|
|
|
+ case CIRCUIT_PURPOSE_S_HSDIR_POST:
|
|
|
|
+ case CIRCUIT_PURPOSE_C_HSDIR_GET:
|
|
case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO:
|
|
case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO:
|
|
/* need to add a new hop */
|
|
/* need to add a new hop */
|
|
tor_assert(extend_info);
|
|
tor_assert(extend_info);
|
|
@@ -2211,7 +2369,9 @@ circuit_get_open_circ_or_launch(entry_connection_t *conn,
|
|
/* If we have specified a particular exit node for our
|
|
/* If we have specified a particular exit node for our
|
|
* connection, then be sure to open a circuit to that exit node.
|
|
* connection, then be sure to open a circuit to that exit node.
|
|
*/
|
|
*/
|
|
- if (desired_circuit_purpose == CIRCUIT_PURPOSE_C_GENERAL) {
|
|
|
|
|
|
+ if (desired_circuit_purpose == CIRCUIT_PURPOSE_C_GENERAL ||
|
|
|
|
+ desired_circuit_purpose == CIRCUIT_PURPOSE_S_HSDIR_POST ||
|
|
|
|
+ desired_circuit_purpose == CIRCUIT_PURPOSE_C_HSDIR_GET) {
|
|
if (conn->chosen_exit_name) {
|
|
if (conn->chosen_exit_name) {
|
|
const node_t *r;
|
|
const node_t *r;
|
|
int opt = conn->chosen_exit_optional;
|
|
int opt = conn->chosen_exit_optional;
|
|
@@ -2319,7 +2479,9 @@ circuit_get_open_circ_or_launch(entry_connection_t *conn,
|
|
|
|
|
|
/* Now trigger things that need to happen when we launch circuits */
|
|
/* Now trigger things that need to happen when we launch circuits */
|
|
|
|
|
|
- if (desired_circuit_purpose == CIRCUIT_PURPOSE_C_GENERAL) {
|
|
|
|
|
|
+ if (desired_circuit_purpose == CIRCUIT_PURPOSE_C_GENERAL ||
|
|
|
|
+ desired_circuit_purpose == CIRCUIT_PURPOSE_C_HSDIR_GET ||
|
|
|
|
+ desired_circuit_purpose == CIRCUIT_PURPOSE_S_HSDIR_POST) {
|
|
/* We just caused a circuit to get built because of this stream.
|
|
/* We just caused a circuit to get built because of this stream.
|
|
* If this stream has caused a _lot_ of circuits to be built, that's
|
|
* If this stream has caused a _lot_ of circuits to be built, that's
|
|
* a bad sign: we should tell the user. */
|
|
* a bad sign: we should tell the user. */
|
|
@@ -2448,6 +2610,8 @@ link_apconn_to_circ(entry_connection_t *apconn, origin_circuit_t *circ,
|
|
/* See if we can use optimistic data on this circuit */
|
|
/* See if we can use optimistic data on this circuit */
|
|
if (optimistic_data_enabled() &&
|
|
if (optimistic_data_enabled() &&
|
|
(circ->base_.purpose == CIRCUIT_PURPOSE_C_GENERAL ||
|
|
(circ->base_.purpose == CIRCUIT_PURPOSE_C_GENERAL ||
|
|
|
|
+ circ->base_.purpose == CIRCUIT_PURPOSE_C_HSDIR_GET ||
|
|
|
|
+ circ->base_.purpose == CIRCUIT_PURPOSE_S_HSDIR_POST ||
|
|
circ->base_.purpose == CIRCUIT_PURPOSE_C_REND_JOINED))
|
|
circ->base_.purpose == CIRCUIT_PURPOSE_C_REND_JOINED))
|
|
apconn->may_use_optimistic_data = 1;
|
|
apconn->may_use_optimistic_data = 1;
|
|
else
|
|
else
|
|
@@ -2568,6 +2732,39 @@ connection_ap_handshake_attach_chosen_circuit(entry_connection_t *conn,
|
|
return 1;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * Return an appropriate circuit purpose for non-rend streams.
|
|
|
|
+ * We don't handle rends here because a rend stream triggers two
|
|
|
|
+ * circuit builds with different purposes, so it is handled elsewhere.
|
|
|
|
+ *
|
|
|
|
+ * This function just figures out what type of hsdir activity this is,
|
|
|
|
+ * and tells us. Everything else is general.
|
|
|
|
+ */
|
|
|
|
+static int
|
|
|
|
+connection_ap_get_nonrend_circ_purpose(const entry_connection_t *conn)
|
|
|
|
+{
|
|
|
|
+ const connection_t *base_conn = ENTRY_TO_CONN(conn);
|
|
|
|
+ tor_assert_nonfatal(!connection_edge_is_rendezvous_stream(
|
|
|
|
+ ENTRY_TO_EDGE_CONN(conn)));
|
|
|
|
+
|
|
|
|
+ if (base_conn->linked_conn &&
|
|
|
|
+ base_conn->linked_conn->type == CONN_TYPE_DIR) {
|
|
|
|
+ /* Set a custom purpose for hsdir activity */
|
|
|
|
+ if (base_conn->linked_conn->purpose == DIR_PURPOSE_UPLOAD_RENDDESC_V2 ||
|
|
|
|
+ base_conn->linked_conn->purpose == DIR_PURPOSE_UPLOAD_HSDESC) {
|
|
|
|
+ return CIRCUIT_PURPOSE_S_HSDIR_POST;
|
|
|
|
+ } else if (base_conn->linked_conn->purpose
|
|
|
|
+ == DIR_PURPOSE_FETCH_RENDDESC_V2 ||
|
|
|
|
+ base_conn->linked_conn->purpose
|
|
|
|
+ == DIR_PURPOSE_FETCH_HSDESC) {
|
|
|
|
+ return CIRCUIT_PURPOSE_C_HSDIR_GET;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* All other purposes are general for now */
|
|
|
|
+ return CIRCUIT_PURPOSE_C_GENERAL;
|
|
|
|
+}
|
|
|
|
+
|
|
/** Try to find a safe live circuit for stream <b>conn</b>. If we find one,
|
|
/** Try to find a safe live circuit for stream <b>conn</b>. If we find one,
|
|
* attach the stream, send appropriate cells, and return 1. Otherwise,
|
|
* attach the stream, send appropriate cells, and return 1. Otherwise,
|
|
* try to launch new circuit(s) for the stream. If we can launch
|
|
* try to launch new circuit(s) for the stream. If we can launch
|
|
@@ -2666,9 +2863,12 @@ connection_ap_handshake_attach_circuit(entry_connection_t *conn)
|
|
}
|
|
}
|
|
|
|
|
|
/* Find the circuit that we should use, if there is one. Otherwise
|
|
/* Find the circuit that we should use, if there is one. Otherwise
|
|
- * launch it. */
|
|
|
|
- retval = circuit_get_open_circ_or_launch(
|
|
|
|
- conn, CIRCUIT_PURPOSE_C_GENERAL, &circ);
|
|
|
|
|
|
+ * launch it
|
|
|
|
+ */
|
|
|
|
+ retval = circuit_get_open_circ_or_launch(conn,
|
|
|
|
+ connection_ap_get_nonrend_circ_purpose(conn),
|
|
|
|
+ &circ);
|
|
|
|
+
|
|
if (retval < 1) {
|
|
if (retval < 1) {
|
|
/* We were either told "-1" (complete failure) or 0 (circuit in
|
|
/* We were either told "-1" (complete failure) or 0 (circuit in
|
|
* progress); we can't attach this stream yet. */
|
|
* progress); we can't attach this stream yet. */
|