|
@@ -54,6 +54,7 @@
|
|
|
#include "rephist.h"
|
|
|
#include "router.h"
|
|
|
#include "routerlist.h"
|
|
|
+#include "config.h"
|
|
|
|
|
|
static void circuit_expire_old_circuits_clientside(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 ||
|
|
|
+ purpose == CIRCUIT_PURPOSE_HS_VANGUARDS ||
|
|
|
purpose == CIRCUIT_PURPOSE_C_REND_JOINED) {
|
|
|
if (circ->timestamp_dirty &&
|
|
|
circ->timestamp_dirty+get_options()->MaxCircuitDirtiness <= now)
|
|
@@ -327,6 +329,7 @@ circuit_get_best(const entry_connection_t *conn,
|
|
|
tor_assert(conn);
|
|
|
|
|
|
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 ||
|
|
@@ -1086,7 +1089,8 @@ circuit_is_available_for_use(const circuit_t *circ)
|
|
|
return 0; /* Don't mess with marked circs */
|
|
|
if (circ->timestamp_dirty)
|
|
|
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.
|
|
|
General purpose circuits are always origin circuits. */
|
|
|
|
|
@@ -1198,6 +1202,25 @@ needs_circuits_for_build(int num)
|
|
|
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,
|
|
|
* 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.
|
|
@@ -1251,7 +1274,7 @@ circuit_predict_and_launch_new(void)
|
|
|
"Have %d clean circs (%d internal), need another internal "
|
|
|
"circ for my hidden service.",
|
|
|
num, num_internal);
|
|
|
- circuit_launch(CIRCUIT_PURPOSE_C_GENERAL, flags);
|
|
|
+ circuit_launch_predicted_hs_circ(flags);
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -1269,7 +1292,8 @@ circuit_predict_and_launch_new(void)
|
|
|
"Have %d clean circs (%d uptime-internal, %d internal), need"
|
|
|
" another hidden service circ.",
|
|
|
num, num_uptime_internal, num_internal);
|
|
|
- circuit_launch(CIRCUIT_PURPOSE_C_GENERAL, flags);
|
|
|
+
|
|
|
+ circuit_launch_predicted_hs_circ(flags);
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -1466,6 +1490,7 @@ circuit_expire_old_circuits_clientside(void)
|
|
|
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_S_ESTABLISH_INTRO ||
|
|
|
circ->purpose == CIRCUIT_PURPOSE_TESTING ||
|
|
@@ -1737,6 +1762,8 @@ circuit_build_failed(origin_circuit_t *circ)
|
|
|
circ->cpath->prev->prev->state == CPATH_STATE_OPEN) {
|
|
|
failed_at_last_hop = 1;
|
|
|
}
|
|
|
+
|
|
|
+ /* Check if we failed at first hop */
|
|
|
if (circ->cpath &&
|
|
|
circ->cpath->state != CPATH_STATE_OPEN &&
|
|
|
! circ->base_.received_destroy) {
|
|
@@ -1888,6 +1915,10 @@ have_enough_path_info(int need_exit)
|
|
|
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_) {
|
|
@@ -1929,6 +1960,55 @@ circuit_should_use_vanguards(uint8_t purpose)
|
|
|
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
|
|
|
* <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
|
|
@@ -1963,10 +2043,12 @@ circuit_launch_by_extend_info(uint8_t purpose,
|
|
|
need_specific_rp = 1;
|
|
|
}
|
|
|
|
|
|
- if ((extend_info || purpose != CIRCUIT_PURPOSE_C_GENERAL) &&
|
|
|
- purpose != CIRCUIT_PURPOSE_TESTING &&
|
|
|
- !circuit_should_use_vanguards(purpose) &&
|
|
|
- !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. */
|
|
|
/* XXX if we're planning to add a hop, perhaps we want to look for
|
|
|
* internal circs rather than exit circs? -RD */
|