Browse Source

Merge branch 'bug20824_v4'

Nick Mathewson 7 years ago
parent
commit
9e8671bb9a
5 changed files with 82 additions and 6 deletions
  1. 3 0
      changes/bug20824
  2. 8 5
      src/or/control.c
  3. 36 0
      src/or/entrynodes.c
  4. 5 1
      src/or/entrynodes.h
  5. 30 0
      src/test/test_entrynodes.c

+ 3 - 0
changes/bug20824

@@ -0,0 +1,3 @@
+  o Minor bugfixes (controller):
+    - Restore the (deprecated) DROPGUARDS controller command.
+      Fixes bug 20824; bugfix on 0.3.0.1-alpha.

+ 8 - 5
src/or/control.c

@@ -4064,17 +4064,20 @@ handle_control_dropguards(control_connection_t *conn,
   smartlist_split_string(args, body, " ",
                          SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
 
-#ifdef ENABLE_LEGACY_GUARD_ALGORITHM
+  static int have_warned = 0;
+  if (! have_warned) {
+    log_warn(LD_CONTROL, "DROPGUARDS is dangerous; make sure you understand "
+             "the risks before using it. It may be removed in a future "
+             "version of Tor.");
+    have_warned = 1;
+  }
+
   if (smartlist_len(args)) {
     connection_printf_to_buf(conn, "512 Too many arguments to DROPGUARDS\r\n");
   } else {
     remove_all_entry_guards();
     send_control_done(conn);
   }
-#else
-  // XXXX
-  connection_printf_to_buf(conn, "512 not supported\r\n");
-#endif
 
   SMARTLIST_FOREACH(args, char *, cp, tor_free(cp));
   smartlist_free(args);

+ 36 - 0
src/or/entrynodes.c

@@ -3252,6 +3252,42 @@ guards_choose_guard(cpath_build_state_t *state,
   return r;
 }
 
+/** Remove all currently listed entry guards for a given guard selection
+ * context.  This frees and replaces <b>gs</b>, so don't use <b>gs</b>
+ * after calling this function. */
+void
+remove_all_entry_guards_for_guard_selection(guard_selection_t *gs)
+{
+  // This function shouldn't exist. XXXX
+  tor_assert(gs != NULL);
+  char *old_name = tor_strdup(gs->name);
+  guard_selection_type_t old_type = gs->type;
+
+  SMARTLIST_FOREACH(gs->sampled_entry_guards, entry_guard_t *, entry, {
+    control_event_guard(entry->nickname, entry->identity, "DROPPED");
+  });
+
+  if (gs == curr_guard_context) {
+    curr_guard_context = NULL;
+  }
+
+  smartlist_remove(guard_contexts, gs);
+  guard_selection_free(gs);
+
+  gs = get_guard_selection_by_name(old_name, old_type, 1);
+  entry_guards_changed_for_guard_selection(gs);
+  tor_free(old_name);
+}
+
+/** Remove all currently listed entry guards. So new ones will be chosen. */
+void
+remove_all_entry_guards(void)
+{
+  // XXXX prop271 this function shouldn't exist, in the new order.
+  // This function shouldn't exist.
+  remove_all_entry_guards_for_guard_selection(get_guard_selection_info());
+}
+
 /** Helper: pick a directory guard, with whatever algorithm is used. */
 const node_t *
 guards_choose_dirguard(circuit_guard_state_t **guard_state_out)

+ 5 - 1
src/or/entrynodes.h

@@ -170,7 +170,8 @@ struct entry_guard_t {
    * we saw them in the state, even if we don't understand them. */
   char *extra_state_fields;
 
-  /** Backpointer to the guard selection that this guard belongs to. */
+  /** Backpointer to the guard selection that this guard belongs to.
+   * The entry_guard_t must never outlive its guard_selection. */
   guard_selection_t *in_selection;
   /**@}*/
 
@@ -548,6 +549,9 @@ STATIC int entry_guard_has_higher_priority(entry_guard_t *a, entry_guard_t *b);
 STATIC char *getinfo_helper_format_single_entry_guard(const entry_guard_t *e);
 #endif
 
+void remove_all_entry_guards_for_guard_selection(guard_selection_t *gs);
+void remove_all_entry_guards(void);
+
 struct bridge_info_t;
 void entry_guard_learned_bridge_identity(const tor_addr_port_t *addrport,
                                          const uint8_t *rsa_id_digest);

+ 30 - 0
src/test/test_entrynodes.c

@@ -2194,6 +2194,35 @@ test_entry_guard_select_and_cancel(void *arg)
   circuit_guard_state_free(guard);
 }
 
+static void
+test_entry_guard_drop_guards(void *arg)
+{
+  (void) arg;
+  int r;
+  const node_t *node = NULL;
+  circuit_guard_state_t *guard;
+  guard_selection_t *gs = get_guard_selection_info();
+
+  // Pick a guard, to get things set up.
+  r = entry_guard_pick_for_circuit(gs, GUARD_USAGE_TRAFFIC, NULL,
+                                   &node, &guard);
+  tt_int_op(r, OP_EQ, 0);
+  tt_int_op(smartlist_len(gs->sampled_entry_guards), OP_GE,
+            DFLT_MIN_FILTERED_SAMPLE_SIZE);
+  tt_ptr_op(gs, OP_EQ, get_guard_selection_info());
+
+  // Drop all the guards!  (This is a bad idea....)
+  remove_all_entry_guards_for_guard_selection(gs);
+  gs = get_guard_selection_info();
+  tt_int_op(smartlist_len(gs->sampled_entry_guards), OP_EQ, 0);
+  tt_int_op(smartlist_len(gs->primary_entry_guards), OP_EQ, 0);
+  tt_int_op(smartlist_len(gs->confirmed_entry_guards), OP_EQ, 0);
+
+ done:
+  circuit_guard_state_free(guard);
+  guard_selection_free(gs);
+}
+
 /* Unit test setup function: Create a fake network, and set everything up
  * for testing the upgrade-a-waiting-circuit code. */
 typedef struct {
@@ -2667,6 +2696,7 @@ struct testcase_t entrynodes_tests[] = {
   BFN_TEST(select_for_circuit_highlevel_confirm_other),
   BFN_TEST(select_for_circuit_highlevel_primary_retry),
   BFN_TEST(select_and_cancel),
+  BFN_TEST(drop_guards),
 
   UPGRADE_TEST(upgrade_a_circuit, "c1-done c2-done"),
   UPGRADE_TEST(upgrade_blocked_by_live_primary_guards, "c1-done c2-done"),