|
@@ -836,6 +836,83 @@ channel_next_with_rsa_identity(channel_t *chan)
|
|
|
return TOR_LIST_NEXT(chan, next_with_same_id);
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+ * Relays run this once an hour to look over our list of channels to other
|
|
|
+ * relays. It prints out some statistics if there are multiple connections
|
|
|
+ * to many relays.
|
|
|
+ *
|
|
|
+ * This function is similar to connection_or_set_bad_connections(),
|
|
|
+ * and probably could be adapted to replace it, if it was modified to actually
|
|
|
+ * take action on any of these connections.
|
|
|
+ */
|
|
|
+void
|
|
|
+channel_check_for_duplicates(void)
|
|
|
+{
|
|
|
+ channel_idmap_entry_t **iter;
|
|
|
+ channel_t *chan;
|
|
|
+ int total_relay_connections = 0, total_relays = 0, total_canonical = 0;
|
|
|
+ int total_half_canonical = 0;
|
|
|
+ int total_gt_one_connection = 0, total_gt_two_connections = 0;
|
|
|
+ int total_gt_four_connections = 0;
|
|
|
+
|
|
|
+ HT_FOREACH(iter, channel_idmap, &channel_identity_map) {
|
|
|
+ int connections_to_relay = 0;
|
|
|
+
|
|
|
+
|
|
|
+ if (!connection_or_digest_is_known_relay((char*)(*iter)->digest))
|
|
|
+ continue;
|
|
|
+
|
|
|
+ total_relays++;
|
|
|
+
|
|
|
+ for (chan = TOR_LIST_FIRST(&(*iter)->channel_list); chan;
|
|
|
+ chan = channel_next_with_rsa_identity(chan)) {
|
|
|
+
|
|
|
+ if (CHANNEL_CONDEMNED(chan) || !CHANNEL_IS_OPEN(chan))
|
|
|
+ continue;
|
|
|
+
|
|
|
+ connections_to_relay++;
|
|
|
+ total_relay_connections++;
|
|
|
+
|
|
|
+ if (chan->is_canonical(chan, 0)) total_canonical++;
|
|
|
+
|
|
|
+ if (!chan->is_canonical_to_peer && chan->is_canonical(chan, 0)
|
|
|
+ && chan->is_canonical(chan, 1)) {
|
|
|
+ total_half_canonical++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (connections_to_relay > 1) total_gt_one_connection++;
|
|
|
+ if (connections_to_relay > 2) total_gt_two_connections++;
|
|
|
+ if (connections_to_relay > 4) total_gt_four_connections++;
|
|
|
+ }
|
|
|
+
|
|
|
+#define MIN_RELAY_CONNECTIONS_TO_WARN 5
|
|
|
+
|
|
|
+
|
|
|
+ if (total_relays > MIN_RELAY_CONNECTIONS_TO_WARN &&
|
|
|
+ total_relay_connections >= 1.5*total_relays) {
|
|
|
+ log_notice(LD_OR,
|
|
|
+ "Your relay has a very large number of connections to other relays. "
|
|
|
+ "Is your outbound address the same as your relay address? "
|
|
|
+ "Found %d connections to %d relays. Found %d current canonical "
|
|
|
+ "connections, in %d of which we were a non-canonical peer. "
|
|
|
+ "%d relays had more than 1 connection, %d had more than 2, and "
|
|
|
+ "%d had more than 4 connections.",
|
|
|
+ total_relay_connections, total_relays, total_canonical,
|
|
|
+ total_half_canonical, total_gt_one_connection,
|
|
|
+ total_gt_two_connections, total_gt_four_connections);
|
|
|
+ } else {
|
|
|
+ log_info(LD_OR, "Performed connection pruning. "
|
|
|
+ "Found %d connections to %d relays. Found %d current canonical "
|
|
|
+ "connections, in %d of which we were a non-canonical peer. "
|
|
|
+ "%d relays had more than 1 connection, %d had more than 2, and "
|
|
|
+ "%d had more than 4 connections.",
|
|
|
+ total_relay_connections, total_relays, total_canonical,
|
|
|
+ total_half_canonical, total_gt_one_connection,
|
|
|
+ total_gt_two_connections, total_gt_four_connections);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
|
|
|
* Initialize a channel
|
|
|
*
|
|
@@ -3323,22 +3400,20 @@ channel_connect(const tor_addr_t *addr, uint16_t port,
|
|
|
*/
|
|
|
|
|
|
int
|
|
|
-channel_is_better(time_t now, channel_t *a, channel_t *b,
|
|
|
- int forgive_new_connections)
|
|
|
+channel_is_better(channel_t *a, channel_t *b)
|
|
|
{
|
|
|
- int a_grace, b_grace;
|
|
|
int a_is_canonical, b_is_canonical;
|
|
|
- int a_has_circs, b_has_circs;
|
|
|
-
|
|
|
-
|
|
|
- * Do not definitively deprecate a new channel with no circuits on it
|
|
|
- * until this much time has passed.
|
|
|
- */
|
|
|
-#define NEW_CHAN_GRACE_PERIOD (15*60)
|
|
|
|
|
|
tor_assert(a);
|
|
|
tor_assert(b);
|
|
|
|
|
|
+
|
|
|
+ * use the one that is still good. */
|
|
|
+ if (!channel_is_bad_for_new_circs(a) && channel_is_bad_for_new_circs(b))
|
|
|
+ return 1;
|
|
|
+ if (channel_is_bad_for_new_circs(a) && !channel_is_bad_for_new_circs(b))
|
|
|
+ return 0;
|
|
|
+
|
|
|
|
|
|
a_is_canonical = channel_is_canonical(a);
|
|
|
b_is_canonical = channel_is_canonical(b);
|
|
@@ -3346,26 +3421,31 @@ channel_is_better(time_t now, channel_t *a, channel_t *b,
|
|
|
if (a_is_canonical && !b_is_canonical) return 1;
|
|
|
if (!a_is_canonical && b_is_canonical) return 0;
|
|
|
|
|
|
+
|
|
|
+ * by the peer */
|
|
|
+ if (a->is_canonical_to_peer && !b->is_canonical_to_peer) return 1;
|
|
|
+ if (!a->is_canonical_to_peer && b->is_canonical_to_peer) return 0;
|
|
|
+
|
|
|
|
|
|
- * Okay, if we're here they tied on canonicity. Next we check if
|
|
|
- * they have any circuits, and if one does and the other doesn't,
|
|
|
- * we prefer the one that does, unless we are forgiving and the
|
|
|
- * one that has no circuits is in its grace period.
|
|
|
+ * Okay, if we're here they tied on canonicity, the prefer the older
|
|
|
+ * connection, so that the adversary can't create a new connection
|
|
|
+ * and try to switch us over to it (which will leak information
|
|
|
+ * about long-lived circuits). Additionally, switching connections
|
|
|
+ * too often makes us more vulnerable to attacks like Torscan and
|
|
|
+ * passive netflow-based equivalents.
|
|
|
+ *
|
|
|
+ * Connections will still only live for at most a week, due to
|
|
|
+ * the check in connection_or_group_set_badness() against
|
|
|
+ * TIME_BEFORE_OR_CONN_IS_TOO_OLD, which marks old connections as
|
|
|
+ * unusable for new circuits after 1 week. That check sets
|
|
|
+ * is_bad_for_new_circs, which is checked in channel_get_for_extend().
|
|
|
+ *
|
|
|
+ * We check channel_is_bad_for_new_circs() above here anyway, for safety.
|
|
|
*/
|
|
|
+ if (channel_when_created(a) < channel_when_created(b)) return 1;
|
|
|
+ else if (channel_when_created(a) > channel_when_created(b)) return 0;
|
|
|
|
|
|
- a_has_circs = (channel_num_circuits(a) > 0);
|
|
|
- b_has_circs = (channel_num_circuits(b) > 0);
|
|
|
- a_grace = (forgive_new_connections &&
|
|
|
- (now < channel_when_created(a) + NEW_CHAN_GRACE_PERIOD));
|
|
|
- b_grace = (forgive_new_connections &&
|
|
|
- (now < channel_when_created(b) + NEW_CHAN_GRACE_PERIOD));
|
|
|
-
|
|
|
- if (a_has_circs && !b_has_circs && !b_grace) return 1;
|
|
|
- if (!a_has_circs && b_has_circs && !a_grace) return 0;
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- if (channel_when_created(a) > channel_when_created(b)) return 1;
|
|
|
+ if (channel_num_circuits(a) > channel_num_circuits(b)) return 1;
|
|
|
else return 0;
|
|
|
}
|
|
|
|
|
@@ -3390,7 +3470,6 @@ channel_get_for_extend(const char *rsa_id_digest,
|
|
|
channel_t *chan, *best = NULL;
|
|
|
int n_inprogress_goodaddr = 0, n_old = 0;
|
|
|
int n_noncanonical = 0, n_possible = 0;
|
|
|
- time_t now = approx_time();
|
|
|
|
|
|
tor_assert(msg_out);
|
|
|
tor_assert(launch_out);
|
|
@@ -3460,7 +3539,7 @@ channel_get_for_extend(const char *rsa_id_digest,
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- if (channel_is_better(now, chan, best, 0))
|
|
|
+ if (channel_is_better(chan, best))
|
|
|
best = chan;
|
|
|
}
|
|
|
|