[tor-commits] [tor/master] Merge maint-0.2.2 for the bug1090-part1-squashed branch

nickm at torproject.org nickm at torproject.org
Wed Apr 27 18:36:24 UTC 2011


commit 8b686d98c47226dfc4d7c87d6a472b592135ae07
Merge: 3256627 99621bc
Author: Nick Mathewson <nickm at torproject.org>
Date:   Wed Apr 27 14:36:30 2011 -0400

    Merge maint-0.2.2 for the bug1090-part1-squashed branch
    
    Resolved conflicts in:
    	doc/tor.1.txt
    	src/or/circuitbuild.c
    	src/or/circuituse.c
    	src/or/connection_edge.c
    	src/or/connection_edge.h
    	src/or/directory.c
    	src/or/rendclient.c
    	src/or/routerlist.c
    	src/or/routerlist.h
    
    These were mostly releated to the routerinfo_t->node_t conversion.

 changes/bug1090-general        |   73 ++++++++++++++++
 changes/bug1090-launch-warning |    5 +
 changes/exitnodes_reliable     |    7 ++
 doc/tor.1.txt                  |   75 ++++++++++++----
 src/or/circuitbuild.c          |  187 +++++++++++++++++++++++-----------------
 src/or/circuitlist.c           |   70 +++++++++++++++
 src/or/circuitlist.h           |    1 +
 src/or/circuituse.c            |   76 ++++++++++------
 src/or/circuituse.h            |    2 +
 src/or/config.c                |   24 +++--
 src/or/connection_edge.c       |  117 +++++++++++++++++++------
 src/or/connection_edge.h       |    4 +-
 src/or/directory.c             |   31 ++++++-
 src/or/or.h                    |   11 ++-
 src/or/rendclient.c            |   85 ++++++++++++++++---
 src/or/rendclient.h            |    1 +
 src/or/rendcommon.c            |    2 +-
 src/or/rendservice.c           |   40 +++++++--
 src/or/router.c                |   20 ++++
 src/or/routerlist.c            |   73 ++++++++++++++--
 src/or/routerlist.h            |    8 ++-
 21 files changed, 712 insertions(+), 200 deletions(-)

diff --cc doc/tor.1.txt
index 5a70cd2,866a702..f24eaba
--- a/doc/tor.1.txt
+++ b/doc/tor.1.txt
@@@ -512,27 -508,55 +526,54 @@@ The following options are useful only f
  
  **ExcludeExitNodes** __node__,__node__,__...__::
      A list of identity fingerprints, nicknames, country codes and address
-     patterns of nodes to never use when picking an exit node. Note that any
+     patterns of nodes to never use when picking an exit node---that is, a
+     node that delivers traffic for you outside the Tor network.   Note that any
      node listed in ExcludeNodes is automatically considered to be part of this
-     list.
- 
- **EntryNodes** __node__,__node__,__...__::
-     A list of identity fingerprints, nicknames, country codes and address
-     patterns of nodes to use for the first hop in normal circuits. These are
-     treated only as preferences unless StrictNodes (see below) is also set.
+     list too.  See also the caveats on the "ExitNodes" option below
  
 -
  **ExitNodes** __node__,__node__,__...__::
      A list of identity fingerprints, nicknames, country codes and address
-     patterns of nodes to use for the last hop in normal exit circuits. These
-     are treated only as preferences unless StrictNodes (see below) is also set.
+     patterns of nodes to use as exit node---that is, a
+     node that delivers traffic for you outside the Tor network. +
+ +
+     Note that if you list too few nodes here, or if you exclude too many exit
+     nodes with ExcludeExitNodes, you can degrade functionality.  For example,
+     if none of the exits you list allows traffic on port 80 or 443, you won't
+     be able to browse the web. +
+ +
+     Note also that not every circuit is used to deliver traffic outside of
+     the Tor network.  It is normal to see non-exit circuits (such as those
+     used to connect to hidden services, those that do directory fetches,
+     those used for self-tests, and so on) that end at a non-exit node.  To
+     keep a node from being used entirely, see ExcludeNodes and StrictNodes. +
+ +
+     The ExcludeNodes option overrides this option: any node listed in both
+     ExitNodes and ExcludeNodes is treated as excluded. +
+ +
+     The .exit address notation, if enabled, overrides this option.
+ 
+ **EntryNodes** __node__,__node__,__...__::
 -    A list of identity fingerprints and nicknames of nodes
 -    to use for the first hop in your normal circuits.  (Country codes and
 -    address patterns are not yet supported.)  This includes all
++    A list of identity fingerprints, nicknames, and country codes of nodes
++    to use for the first hop in your normal circuits.
++    This includes all
+     circuits except for direct connections to directory servers.  The Bridge
+     option overrides this option; if you have configured bridges and
+     UseBridges is 1, the Bridges are used as your entry nodes. +
+ +
+     The ExcludeNodes option overrides this option: any node listed in both
+     EntryNodes and ExcludeNodes is treated as excluded.
  
  **StrictNodes** **0**|**1**::
-     If 1 and EntryNodes config option is set, Tor will never use any nodes
-     besides those listed in EntryNodes for the first hop of a normal circuit.
-     If 1 and ExitNodes config option is set, Tor will never use any nodes
-     besides those listed in ExitNodes for the last hop of a normal exit
-     circuit. Note that Tor might still use these nodes for non-exit circuits
-     such as one-hop directory fetches or hidden service support circuits.
+     If StrictNodes is set to 1, Tor will treat the ExcludeNodes option as a
+     requirement to follow for all the circuits you generate, even if doing so
+     will break functionality for you.  If StrictNodes is set to 0, Tor will
+     still try to avoid nodes in the ExcludeNodes list, but it will err on the
+     side of avoiding unexpected errors.  Specifically, StrictNodes 0 tells
+     Tor that it is okay to use an excluded node when it is *necessary* to
+     perform self-tests, connect to
+     a hidden service, provide a hidden service to a client, fulfill a .exit
+     request, upload directory information, or download directory information.
+     (Default: 0)
  
  **FascistFirewall** **0**|**1**::
      If 1, Tor will only create outgoing connections to ORs running on ports
diff --cc src/or/circuitbuild.c
index ff656fd,90572d5..cc78d99
--- a/src/or/circuitbuild.c
+++ b/src/or/circuitbuild.c
@@@ -2673,18 -2686,26 +2674,25 @@@ choose_good_exit_server_general(int nee
        n_supported[i] = -1;
        continue; /* skip routers that are known to be down or bad exits */
      }
-     if (node_is_unreliable(node, need_uptime, need_capacity, 0) &&
-         (!options->ExitNodes ||
-          !routerset_contains_node(options->ExitNodes, node))) {
-       /* FFFF Someday, differentiate between a routerset that names
-        * routers, and a routerset that names countries, and only do this
-        * check if they've asked for specific exit relays. Or if the country
-        * they ask for is rare. Or something. */
 -
+     if (options->_ExcludeExitNodesUnion &&
 -        routerset_contains_router(options->_ExcludeExitNodesUnion, router)) {
++        routerset_contains_node(options->_ExcludeExitNodesUnion, node)) {
        n_supported[i] = -1;
-       continue; /* skip routers that are not suitable, unless we have
-                  * ExitNodes set, in which case we asked for it */
+       continue; /* user asked us not to use it, no matter what */
+     }
+     if (options->ExitNodes &&
 -        !routerset_contains_router(options->ExitNodes, router)) {
++        !routerset_contains_node(options->ExitNodes, node)) {
+       n_supported[i] = -1;
+       continue; /* not one of our chosen exit nodes */
+     }
+ 
 -    if (router_is_unreliable(router, need_uptime, need_capacity, 0)) {
++    if (node_is_unreliable(node, need_uptime, need_capacity, 0)) {
+       n_supported[i] = -1;
+       continue; /* skip routers that are not suitable.  Don't worry if
+                  * this makes us reject all the possible routers: if so,
+                  * we'll retry later in this function with need_update and
+                  * need_capacity set to 0. */
      }
 -    if (!(router->is_valid || options->_AllowInvalid & ALLOW_INVALID_EXIT)) {
 +    if (!(node->is_valid || options->_AllowInvalid & ALLOW_INVALID_EXIT)) {
        /* if it's invalid and we don't want it */
        n_supported[i] = -1;
  //      log_fn(LOG_DEBUG,"Skipping node %s (index %d) -- invalid router.",
@@@ -2704,10 -2724,11 +2712,10 @@@
      }
      n_supported[i] = 0;
      /* iterate over connections */
 -    SMARTLIST_FOREACH(connections, connection_t *, conn,
 -    {
 +    SMARTLIST_FOREACH_BEGIN(connections, connection_t *, conn) {
        if (!ap_stream_wants_exit_attention(conn))
          continue; /* Skip everything but APs in CIRCUIT_WAIT */
-       if (connection_ap_can_use_exit(TO_EDGE_CONN(conn), node, 1)) {
 -      if (connection_ap_can_use_exit(TO_EDGE_CONN(conn), router)) {
++      if (connection_ap_can_use_exit(TO_EDGE_CONN(conn), node)) {
          ++n_supported[i];
  //        log_fn(LOG_DEBUG,"%s is supported. n_supported[%d] now %d.",
  //               router->nickname, i, n_supported[i]);
@@@ -2741,22 -2762,13 +2749,14 @@@
    /* If any routers definitely support any pending connections, choose one
     * at random. */
    if (best_support > 0) {
-     smartlist_t *supporting = smartlist_create(), *use = smartlist_create();
+     smartlist_t *supporting = smartlist_create();
  
 -    for (i = 0; i < smartlist_len(dir->routers); i++)
 -      if (n_supported[i] == best_support)
 -        smartlist_add(supporting, smartlist_get(dir->routers, i));
 +    SMARTLIST_FOREACH(the_nodes, const node_t *, node, {
 +      if (n_supported[node_sl_idx] == best_support)
 +        smartlist_add(supporting, (void*)node);
 +    });
  
-     routersets_get_node_disjunction(use, supporting, options->ExitNodes,
-                                options->_ExcludeExitNodesUnion, 1);
-     if (smartlist_len(use) == 0 && options->ExitNodes &&
-         !options->StrictNodes) { /* give up on exitnodes and try again */
-       routersets_get_node_disjunction(use, supporting, NULL,
-                                  options->_ExcludeExitNodesUnion, 1);
-     }
-     node = node_sl_choose_by_bandwidth(use, WEIGHT_FOR_EXIT);
-     smartlist_free(use);
 -    router = routerlist_sl_choose_by_bandwidth(supporting, WEIGHT_FOR_EXIT);
++    node = node_sl_choose_by_bandwidth(supporting, WEIGHT_FOR_EXIT);
      smartlist_free(supporting);
    } else {
      /* Either there are no pending connections, or no routers even seem to
@@@ -2786,32 -2797,20 +2785,21 @@@
      for (attempt = 0; attempt < 2; attempt++) {
        /* try once to pick only from routers that satisfy a needed port,
         * then if there are none, pick from any that support exiting. */
 -      for (i = 0; i < smartlist_len(dir->routers); i++) {
 -        router = smartlist_get(dir->routers, i);
 -        if (n_supported[i] != -1 &&
 -            (attempt || router_handles_some_port(router, needed_ports))) {
 +      SMARTLIST_FOREACH_BEGIN(the_nodes, const node_t *, node) {
 +        if (!node_has_descriptor(node))
 +          continue;
 +        if (n_supported[node_sl_idx] != -1 &&
 +            (attempt || node_handles_some_port(node, needed_ports))) {
  //          log_fn(LOG_DEBUG,"Try %d: '%s' is a possibility.",
  //                 try, router->nickname);
 -          smartlist_add(supporting, router);
 +          smartlist_add(supporting, (void*)node);
          }
 -      }
 +      } SMARTLIST_FOREACH_END(node);
  
-       routersets_get_node_disjunction(use, supporting, options->ExitNodes,
-                                  options->_ExcludeExitNodesUnion, 1);
-       if (smartlist_len(use) == 0 && options->ExitNodes &&
-           !options->StrictNodes) { /* give up on exitnodes and try again */
-         routersets_get_node_disjunction(use, supporting, NULL,
-                                    options->_ExcludeExitNodesUnion, 1);
-       }
-       /* FFF sometimes the above results in null, when the requested
-        * exit node is considered down by the consensus. we should pick
-        * it anyway, since the user asked for it. */
-       node = node_sl_choose_by_bandwidth(use, WEIGHT_FOR_EXIT);
 -      router = routerlist_sl_choose_by_bandwidth(supporting, WEIGHT_FOR_EXIT);
 -      if (router)
++      node = node_sl_choose_by_bandwidth(supporting, WEIGHT_FOR_EXIT);
 +      if (node)
          break;
        smartlist_clear(supporting);
-       smartlist_clear(use);
      }
      SMARTLIST_FOREACH(needed_ports, uint16_t *, cp, tor_free(cp));
      smartlist_free(needed_ports);
@@@ -2820,14 -2818,15 +2807,15 @@@
    }
  
    tor_free(n_supported);
 -  if (router) {
 -    log_info(LD_CIRC, "Chose exit server '%s'", router->nickname);
 -    return router;
 +  if (node) {
 +    log_info(LD_CIRC, "Chose exit server '%s'", node_get_nickname(node));
 +    return node;
    }
-   if (options->ExitNodes && options->StrictNodes) {
+   if (options->ExitNodes) {
      log_warn(LD_CIRC,
-              "No specified exit routers seem to be running, and "
-              "StrictNodes is set: can't choose an exit.");
+              "No specified %sexit routers seem to be running: "
+              "can't choose an exit.",
+              options->_ExcludeExitNodesUnion ? "non-excluded " : "");
    }
    return NULL;
  }
@@@ -3990,15 -3974,16 +3990,17 @@@ entry_guards_prepend_from_config(or_opt
  
    /* Split entry guards into those on the list and those not. */
  
-   /* Now that we allow countries and IP ranges in EntryNodes, this is
-    * potentially an enormous list. It's not so bad though because we
-    * only call this function when a) we're making a new circuit, and b)
-    * we've called directory_info_has_arrived() or changed our EntryNodes
-    * since the last time we made a circuit. */
-   routerset_get_all_nodes(entry_nodes, options->EntryNodes, 0);
+   /* XXXX023 Now that we allow countries and IP ranges in EntryNodes, this is
+    *  potentially an enormous list. For now, we disable such values for
+    *  EntryNodes in options_validate(); really, this wants a better solution.
+    *  Perhaps we should do this calculation once whenever the list of routers
+    *  changes or the entrynodes setting changes.
+    */
 -  routerset_get_all_routers(entry_routers, options->EntryNodes,
 -                            options->ExcludeNodes, 0);
 -  SMARTLIST_FOREACH(entry_routers, routerinfo_t *, ri,
 -                    smartlist_add(entry_fps,ri->cache_info.identity_digest));
++  routerset_get_all_nodes(entry_nodes, options->EntryNodes,
++                          options->ExcludeNodes, 0);
 +  SMARTLIST_FOREACH(entry_nodes, const node_t *,node,
 +                    smartlist_add(entry_fps, (void*)node->identity));
 +
    SMARTLIST_FOREACH(entry_guards, entry_guard_t *, e, {
      if (smartlist_digest_isin(entry_fps, e->identity))
        smartlist_add(old_entry_guards_on_list, e);
@@@ -4018,19 -4003,15 +4020,15 @@@
    /* First, the previously configured guards that are in EntryNodes. */
    smartlist_add_all(entry_guards, old_entry_guards_on_list);
    /* Next, the rest of EntryNodes */
 -  SMARTLIST_FOREACH(entry_routers, routerinfo_t *, ri, {
 -    add_an_entry_guard(ri, 0);
 +  SMARTLIST_FOREACH(entry_nodes, const node_t *, node, {
 +    add_an_entry_guard(node, 0);
    });
-   /* Finally, the remaining previously configured guards that are not in
-    * EntryNodes, unless we're strict in which case we drop them */
-   if (options->StrictNodes) {
-     SMARTLIST_FOREACH(old_entry_guards_not_on_list, entry_guard_t *, e,
-                       entry_guard_free(e));
-   } else {
-     smartlist_add_all(entry_guards, old_entry_guards_not_on_list);
-   }
+   /* Finally, free the remaining previously configured guards that are not in
+    * EntryNodes. */
+   SMARTLIST_FOREACH(old_entry_guards_not_on_list, entry_guard_t *, e,
+                     entry_guard_free(e));
  
 -  smartlist_free(entry_routers);
 +  smartlist_free(entry_nodes);
    smartlist_free(entry_fps);
    smartlist_free(old_entry_guards_on_list);
    smartlist_free(old_entry_guards_not_on_list);
@@@ -4098,17 -4066,19 +4084,18 @@@ choose_random_entry(cpath_build_state_
  
   retry:
    smartlist_clear(live_entry_guards);
 -  SMARTLIST_FOREACH(entry_guards, entry_guard_t *, entry,
 -    {
 +  SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, entry) {
        const char *msg;
 -      r = entry_is_live(entry, need_uptime, need_capacity, 0, &msg);
 -      if (!r)
 +      node = entry_is_live(entry, need_uptime, need_capacity, 0, &msg);
 +      if (!node)
          continue; /* down, no point */
 -      if (r == chosen_exit)
 +      if (node == chosen_exit)
          continue; /* don't pick the same node for entry and exit */
 -      if (consider_exit_family && smartlist_isin(exit_family, r))
 +      if (consider_exit_family && smartlist_isin(exit_family, node))
          continue; /* avoid relays that are family members of our exit */
+ #if 0 /* since EntryNodes is always strict now, this clause is moot */
        if (options->EntryNodes &&
 -          !routerset_contains_router(options->EntryNodes, r)) {
 +          !routerset_contains_node(options->EntryNodes, node)) {
          /* We've come to the end of our preferred entry nodes. */
          if (smartlist_len(live_entry_guards))
            goto choose_and_finish; /* only choose from the ones we like */
@@@ -4121,7 -4091,8 +4108,8 @@@
                     "No relays from EntryNodes available. Using others.");
          }
        }
+ #endif
 -      smartlist_add(live_entry_guards, r);
 +      smartlist_add(live_entry_guards, (void*)node);
        if (!entry->made_contact) {
          /* Always start with the first not-yet-contacted entry
           * guard. Otherwise we might add several new ones, pick
@@@ -4171,10 -4142,14 +4159,14 @@@
        need_capacity = 0;
        goto retry;
      }
+ #if 0
+     /* Removing this retry logic: if we only allow one exit, and it is in the
+        same family as all our entries, then we are just plain not going to win
+        here. */
 -    if (!r && entry_list_is_constrained(options) && consider_exit_family) {
 -      /* still no? if we're using bridges,
 -       * and our chosen exit is in the same family as all our
 -       * bridges, then be flexible about families. */
 +    if (!node && entry_list_is_constrained(options) && consider_exit_family) {
 +      /* still no? if we're using bridges or have strictentrynodes
 +       * set, and our chosen exit is in the same family as all our
 +       * bridges/entry guards, then be flexible about families. */
        consider_exit_family = 0;
        goto retry;
      }
diff --cc src/or/circuituse.c
index e58d5e0,fd1cf6b..30fd818
--- a/src/or/circuituse.c
+++ b/src/or/circuituse.c
@@@ -128,7 -127,7 +128,7 @@@ circuit_is_acceptable(circuit_t *circ, 
          return 0;
        }
      }
-     if (exitnode && !connection_ap_can_use_exit(conn, exitnode, 0)) {
 -    if (exitrouter && !connection_ap_can_use_exit(conn, exitrouter)) {
++    if (exitnode && !connection_ap_can_use_exit(conn, exitnode)) {
        /* can't exit from this router */
        return 0;
      }
@@@ -505,14 -511,14 +512,14 @@@ circuit_stream_is_being_handled(edge_co
        if (build_state->is_internal || build_state->onehop_tunnel)
          continue;
  
 -      exitrouter = build_state_get_exit_router(build_state);
 -      if (exitrouter && (!need_uptime || build_state->need_uptime)) {
 +      exitnode = build_state_get_exit_node(build_state);
 +      if (exitnode && (!need_uptime || build_state->need_uptime)) {
          int ok;
          if (conn) {
-           ok = connection_ap_can_use_exit(conn, exitnode, 0);
 -          ok = connection_ap_can_use_exit(conn, exitrouter);
++          ok = connection_ap_can_use_exit(conn, exitnode);
          } else {
 -          addr_policy_result_t r = compare_addr_to_addr_policy(
 -              0, port, exitrouter->exit_policy);
 +          addr_policy_result_t r;
 +          r = compare_addr_to_node_policy(0, port, exitnode);
            ok = r != ADDR_POLICY_REJECTED && r != ADDR_POLICY_PROBABLY_REJECTED;
          }
          if (ok) {
@@@ -1279,11 -1293,12 +1286,12 @@@ circuit_get_open_circ_or_launch(edge_co
      } else {
        /* XXXX023 Duplicates checks in connection_ap_handshake_attach_circuit:
         * refactor into a single function? */
 -      routerinfo_t *router = router_get_by_nickname(conn->chosen_exit_name, 1);
 +      const node_t *node = node_get_by_nickname(conn->chosen_exit_name, 1);
        int opt = conn->chosen_exit_optional;
-       if (node && !connection_ap_can_use_exit(conn, node, 0)) {
 -      if (router && !connection_ap_can_use_exit(conn, router)) {
++      if (node && !connection_ap_can_use_exit(conn, node)) {
          log_fn(opt ? LOG_INFO : LOG_WARN, LD_APP,
-                "Requested exit point '%s' would refuse request. %s.",
+                "Requested exit point '%s' is excluded or "
+                "would refuse request. %s.",
                 conn->chosen_exit_name, opt ? "Trying others" : "Closing");
          if (opt) {
            conn->chosen_exit_optional = 0;
@@@ -1601,9 -1627,10 +1620,10 @@@ connection_ap_handshake_attach_circuit(
          }
          return -1;
        }
-       if (node && !connection_ap_can_use_exit(conn, node, 0)) {
 -      if (router && !connection_ap_can_use_exit(conn, router)) {
++      if (node && !connection_ap_can_use_exit(conn, node)) {
          log_fn(opt ? LOG_INFO : LOG_WARN, LD_APP,
-                "Requested exit point '%s' would refuse request. %s.",
+                "Requested exit point '%s' is excluded or "
+                "would refuse request. %s.",
                 conn->chosen_exit_name, opt ? "Trying others" : "Closing");
          if (opt) {
            conn->chosen_exit_optional = 0;
diff --cc src/or/connection_edge.c
index 508b06b,082cd5f..29ab6c5
--- a/src/or/connection_edge.c
+++ b/src/or/connection_edge.c
@@@ -808,6 -809,56 +809,56 @@@ clear_trackexithost_mappings(const cha
    tor_free(suffix);
  }
  
+ /** Remove all TRACKEXIT mappings from the addressmap for which the target
+  * host is unknown or no longer allowed. */
+ void
+ addressmap_clear_excluded_trackexithosts(or_options_t *options)
+ {
+   const routerset_t *allow_nodes = options->ExitNodes;
+   const routerset_t *exclude_nodes = options->_ExcludeExitNodesUnion;
+ 
+   if (!addressmap)
+     return;
+   if (routerset_is_empty(allow_nodes))
+     allow_nodes = NULL;
+   if (allow_nodes == NULL && routerset_is_empty(exclude_nodes))
+     return;
+ 
+   STRMAP_FOREACH_MODIFY(addressmap, address, addressmap_entry_t *, ent) {
+     size_t len;
+     const char *target = ent->new_address, *dot;
+     char *nodename;
 -    routerinfo_t *ri; /* XXX023 Use node_t. */
++    const node_t *node;
+ 
+     if (strcmpend(target, ".exit")) {
+       /* Not a .exit mapping */
+       continue;
+     } else if (ent->source != ADDRMAPSRC_TRACKEXIT) {
+       /* Not a trackexit mapping. */
+       continue;
+     }
+     len = strlen(target);
+     if (len < 6)
+       continue; /* malformed. */
+     dot = target + len - 6; /* dot now points to just before .exit */
+     dot = strrchr(dot, '.'); /* dot now points to the . before .exit or NULL */
+     if (!dot) {
+       nodename = tor_strndup(target, len-5);
+     } else {
+       nodename = tor_strndup(dot+1, strlen(dot+1)-5);
+     }
 -    ri = router_get_by_nickname(nodename, 0);
++    node = node_get_by_nickname(nodename, 0);
+     tor_free(nodename);
 -    if (!ri ||
 -        (allow_nodes && !routerset_contains_router(allow_nodes, ri)) ||
 -        routerset_contains_router(exclude_nodes, ri)) {
++    if (!node ||
++        (allow_nodes && !routerset_contains_node(allow_nodes, node)) ||
++        routerset_contains_node(exclude_nodes, node)) {
+       /* We don't know this one, or we want to be rid of it. */
+       addressmap_ent_remove(address, ent);
+       MAP_DEL_CURRENT(address);
+     }
+   } STRMAP_FOREACH_END;
+ }
+ 
  /** Remove all entries from the addressmap that were set via the
   * configuration file or the command line. */
  void
@@@ -1607,10 -1662,19 +1662,18 @@@ connection_ap_handshake_rewrite_and_att
      /* foo.exit -- modify conn->chosen_exit_node to specify the exit
       * node, and conn->address to hold only the address portion. */
      char *s = strrchr(socks->address,'.');
+ 
+     /* If StrictNodes is not set, then .exit overrides ExcludeNodes. */
+     routerset_t *excludeset = options->StrictNodes ?
+       options->_ExcludeExitNodesUnion : options->ExcludeExitNodes;
 -    /*XXX023 make this a node_t. */
 -    routerinfo_t *router;
++    const node_t *node;
+ 
      tor_assert(!automap);
      if (s) {
+       /* The address was of the form "(stuff).(name).exit */
        if (s[1] != '\0') {
          conn->chosen_exit_name = tor_strdup(s+1);
 -        router = router_get_by_nickname(conn->chosen_exit_name, 1);
++        node = node_get_by_nickname(conn->chosen_exit_name, 1);
          if (remapped_to_exit) /* 5 tries before it expires the addressmap */
            conn->chosen_exit_retries = TRACKHOSTEXITS_RETRIES;
          *s = 0;
@@@ -1623,20 -1688,33 +1687,34 @@@
          return -1;
        }
      } else {
-       const node_t *r;
+       /* It looks like they just asked for "foo.exit". */
++
        conn->chosen_exit_name = tor_strdup(socks->address);
-       r = node_get_by_nickname(conn->chosen_exit_name, 1);
-       *socks->address = 0;
-       if (r) {
-         node_get_address_string(r, socks->address, sizeof(socks->address));
-       } else {
-         log_warn(LD_APP,
-                  "Unrecognized server in exit address '%s.exit'. Refusing.",
-                  safe_str_client(socks->address));
-         connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
-         return -1;
 -      router = router_get_by_nickname(conn->chosen_exit_name, 1);
 -      if (router) {
++      node = node_get_by_nickname(conn->chosen_exit_name, 1);
++      if (node) {
+         *socks->address = 0;
 -        strlcpy(socks->address, router->address, sizeof(socks->address));
++        node_get_address_string(node, socks->address, sizeof(socks->address));
        }
      }
+     /* Now make sure that the chosen exit exists... */
 -    if (!router) {
++    if (!node) {
+       log_warn(LD_APP,
+                "Unrecognized relay in exit address '%s.exit'. Refusing.",
+                safe_str_client(socks->address));
+       connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
+       return -1;
+     }
+     /* ...and make sure that it isn't excluded. */
 -    if (routerset_contains_router(excludeset, router)) {
++    if (routerset_contains_node(excludeset, node)) {
+       log_warn(LD_APP,
+                "Excluded relay in exit address '%s.exit'. Refusing.",
+                safe_str_client(socks->address));
+       connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
+       return -1;
+     }
+     /* XXXX022-1090 Should we also allow foo.bar.exit if ExitNodes is set and
+        Bar is not listed in it?  I say yes, but our revised manpage branch
+        implies no. */
    }
  
    if (addresstype != ONION_HOSTNAME) {
@@@ -2977,13 -3044,9 +3055,9 @@@ connection_edge_is_rendezvous_stream(ed
   * to exit from it, or 0 if it probably will not allow it.
   * (We might be uncertain if conn's destination address has not yet been
   * resolved.)
-  *
-  * If <b>excluded_means_no</b> is 1 and Exclude*Nodes is set and excludes
-  * this relay, return 0.
   */
  int
- connection_ap_can_use_exit(edge_connection_t *conn, const node_t *exit,
-                            int excluded_means_no)
 -connection_ap_can_use_exit(edge_connection_t *conn, routerinfo_t *exit)
++connection_ap_can_use_exit(edge_connection_t *conn, const node_t *exit)
  {
    or_options_t *options = get_options();
  
@@@ -3027,17 -3096,8 +3101,8 @@@
        return 0;
    }
    if (options->_ExcludeExitNodesUnion &&
-       (options->StrictNodes || excluded_means_no) &&
 -      routerset_contains_router(options->_ExcludeExitNodesUnion, exit)) {
 +      routerset_contains_node(options->_ExcludeExitNodesUnion, exit)) {
-     /* If we are trying to avoid this node as exit, and we have StrictNodes
-      * set, then this is not a suitable exit. Refuse it.
-      *
-      * If we don't have StrictNodes set, then this function gets called in
-      * two contexts. First, we've got a circuit open and we want to know
-      * whether we can use it. In that case, we somehow built this circuit
-      * despite having the last hop in ExcludeExitNodes, so we should be
-      * willing to use it. Second, we are evaluating whether this is an
-      * acceptable exit for a new circuit. In that case, skip it. */
+     /* Not a suitable exit. Refuse it. */
      return 0;
    }
  
diff --cc src/or/connection_edge.h
index 62a79db,70d0dd2..562db5b
--- a/src/or/connection_edge.h
+++ b/src/or/connection_edge.h
@@@ -48,9 -47,7 +48,8 @@@ int connection_exit_begin_conn(cell_t *
  int connection_exit_begin_resolve(cell_t *cell, or_circuit_t *circ);
  void connection_exit_connect(edge_connection_t *conn);
  int connection_edge_is_rendezvous_stream(edge_connection_t *conn);
 -int connection_ap_can_use_exit(edge_connection_t *conn, routerinfo_t *exit);
 +int connection_ap_can_use_exit(edge_connection_t *conn,
-                                const node_t *exit,
-                                int excluded_means_no);
++                               const node_t *exit);
  void connection_ap_expire_beginning(void);
  void connection_ap_attach_pending(void);
  void connection_ap_fail_onehop(const char *failed_digest,
diff --cc src/or/directory.c
index 6bef581,0c095fe..33ebf52
--- a/src/or/directory.c
+++ b/src/or/directory.c
@@@ -296,6 -291,16 +300,16 @@@ directory_post_to_dirservers(uint8_t di
        if ((type & ds->type) == 0)
          continue;
  
+       if (options->ExcludeNodes && options->StrictNodes &&
 -          routerset_contains_routerstatus(options->ExcludeNodes, rs)) {
++          routerset_contains_routerstatus(options->ExcludeNodes, rs, -1)) {
+         log_warn(LD_DIR, "Wanted to contact authority '%s' for %s, but "
+                  "it's in our ExcludedNodes list and StrictNodes is set. "
+                  "Skipping.",
+                  ds->nickname,
+                  dir_conn_purpose_to_string(dir_purpose));
+         continue;
+       }
+ 
        found = 1; /* at least one authority of this type was listed */
        if (dir_purpose == DIR_PURPOSE_UPLOAD_DIR)
          ds->has_accepted_serverdesc = 0;
@@@ -527,13 -510,15 +541,15 @@@ directory_initiate_command_routerstatus
                                               time_t if_modified_since,
                                               const rend_data_t *rend_query)
  {
+   or_options_t *options = get_options();
 -  routerinfo_t *router;
 +  const node_t *node;
    char address_buf[INET_NTOA_BUF_LEN+1];
    struct in_addr in;
    const char *address;
    tor_addr_t addr;
 -  router = router_get_by_digest(status->identity_digest);
 +  node = node_get_by_id(status->identity_digest);
+ 
 -  if (!router && anonymized_connection) {
 +  if (!node && anonymized_connection) {
      log_info(LD_DIR, "Not sending anonymized request to directory '%s'; we "
                       "don't have its router descriptor.", status->nickname);
      return;
@@@ -546,6 -530,17 +562,17 @@@
      address = address_buf;
    }
    tor_addr_from_ipv4h(&addr, status->addr);
+ 
+   if (options->ExcludeNodes && options->StrictNodes &&
 -      routerset_contains_routerstatus(options->ExcludeNodes, status)) {
++      routerset_contains_routerstatus(options->ExcludeNodes, status, -1)) {
+     log_warn(LD_DIR, "Wanted to contact directory mirror '%s' for %s, but "
+              "it's in our ExcludedNodes list and StrictNodes is set. "
+              "Skipping. This choice might make your Tor not work.",
+              status->nickname,
+              dir_conn_purpose_to_string(dir_purpose));
+     return;
+   }
+ 
    directory_initiate_command_rend(address, &addr,
                               status->or_port, status->dir_port,
                               status->version_supports_conditional_consensus,
diff --cc src/or/rendclient.c
index 47161eb,65e632f..da6cfa3
--- a/src/or/rendclient.c
+++ b/src/or/rendclient.c
@@@ -753,29 -753,78 +756,78 @@@ rend_client_get_random_intro(const rend
      return NULL;
    }
  
+   /* See if we can get a node that complies with ExcludeNodes */
+   if ((result = rend_client_get_random_intro_impl(entry, 1, 1)))
+     return result;
+   /* If not, and StrictNodes is not set, see if we can return any old node
+    */
+   if (!get_options()->StrictNodes)
+     return rend_client_get_random_intro_impl(entry, 0, 1);
+   return NULL;
+ }
+ 
+ /** As rend_client_get_random_intro, except assume that StrictNodes is set
+  * iff <b>strict</b> is true. If <b>warnings</b> is false, don't complain
+  * to the user when we're out of nodes, even if StrictNodes is true.
+  */
+ static extend_info_t *
+ rend_client_get_random_intro_impl(const rend_cache_entry_t *entry,
+                                   const int strict,
+                                   const int warnings)
+ {
+   int i;
+ 
+   rend_intro_point_t *intro;
 -  routerinfo_t *router;
+   or_options_t *options = get_options();
+   smartlist_t *usable_nodes;
+   int n_excluded = 0;
+ 
+   /* We'll keep a separate list of the usable nodes.  If this becomes empty,
+    * no nodes are usable.  */
+   usable_nodes = smartlist_create();
+   smartlist_add_all(usable_nodes, entry->parsed->intro_nodes);
+ 
   again:
-   if (smartlist_len(entry->parsed->intro_nodes) == 0)
+   if (smartlist_len(usable_nodes) == 0) {
+     if (n_excluded && get_options()->StrictNodes && warnings) {
+       /* We only want to warn if StrictNodes is really set. Otherwise
+        * we're just about to retry anyways.
+        */
+       log_warn(LD_REND, "All introduction points for hidden service are "
+                "at excluded relays, and StrictNodes is set. Skipping.");
+     }
+     smartlist_free(usable_nodes);
      return NULL;
+   }
  
-   i = crypto_rand_int(smartlist_len(entry->parsed->intro_nodes));
-   intro = smartlist_get(entry->parsed->intro_nodes, i);
+   i = crypto_rand_int(smartlist_len(usable_nodes));
+   intro = smartlist_get(usable_nodes, i);
    /* Do we need to look up the router or is the extend info complete? */
    if (!intro->extend_info->onion_key) {
 +    const node_t *node;
      if (tor_digest_is_zero(intro->extend_info->identity_digest))
 -      router = router_get_by_hexdigest(intro->extend_info->nickname);
 +      node = node_get_by_hex_id(intro->extend_info->nickname);
      else
 -      router = router_get_by_digest(intro->extend_info->identity_digest);
 -    if (!router) {
 +      node = node_get_by_id(intro->extend_info->identity_digest);
 +    if (!node) {
        log_info(LD_REND, "Unknown router with nickname '%s'; trying another.",
                 intro->extend_info->nickname);
-       rend_intro_point_free(intro);
-       smartlist_del(entry->parsed->intro_nodes, i);
+       smartlist_del(usable_nodes, i);
        goto again;
      }
      extend_info_free(intro->extend_info);
 -    intro->extend_info = extend_info_from_router(router);
 +    intro->extend_info = extend_info_from_node(node);
    }
+   /* Check if we should refuse to talk to this router. */
+   if (options->ExcludeNodes && strict &&
+       routerset_contains_extendinfo(options->ExcludeNodes,
+                                     intro->extend_info)) {
+     n_excluded++;
+     smartlist_del(usable_nodes, i);
+     goto again;
+   }
+ 
+   smartlist_free(usable_nodes);
    return extend_info_dup(intro->extend_info);
  }
  
diff --cc src/or/router.c
index eb4d6b5,0ef4728..8edbb47
--- a/src/or/router.c
+++ b/src/or/router.c
@@@ -849,14 -847,33 +849,34 @@@ decide_to_advertise_dirport(or_options_
  void
  consider_testing_reachability(int test_or, int test_dir)
  {
 -  routerinfo_t *me = router_get_my_routerinfo();
 +  const routerinfo_t *me = router_get_my_routerinfo();
    int orport_reachable = check_whether_orport_reachable();
    tor_addr_t addr;
+   or_options_t *options = get_options();
    if (!me)
      return;
  
 -  if (routerset_contains_router(options->ExcludeNodes, me) &&
++  if (routerset_contains_router(options->ExcludeNodes, me, -1) &&
+       options->StrictNodes) {
+     /* If we've excluded ourself, and StrictNodes is set, we can't test
+      * ourself. */
+     if (test_or || test_dir) {
+ #define SELF_EXCLUDED_WARN_INTERVAL 3600
+       static ratelim_t warning_limit=RATELIM_INIT(SELF_EXCLUDED_WARN_INTERVAL);
+       char *msg;
+       if ((msg = rate_limit_log(&warning_limit, approx_time()))) {
+         log_warn(LD_CIRC, "Can't peform self-tests for this relay: we have "
+                  "listed ourself in ExcludeNodes, and StrictNodes is set. "
+                  "We cannot learn whether we are usable, and will not "
+                  "be able to advertise ourself.%s", msg);
+         tor_free(msg);
+       }
+     }
+     return;
+   }
+ 
    if (test_or && (!orport_reachable || !circuit_enough_testing_circs())) {
 +    extend_info_t *ei;
      log_info(LD_CIRC, "Testing %s of my ORPort: %s:%d.",
               !orport_reachable ? "reachability" : "bandwidth",
               me->address, me->or_port);
diff --cc src/or/routerlist.c
index 8c68a34,d9f099b..d5dc478
--- a/src/or/routerlist.c
+++ b/src/or/routerlist.c
@@@ -1072,10 -1067,11 +1072,11 @@@ router_pick_trusteddirserver(authority_
   * If the _PDS_PREFER_TUNNELED_DIR_CONNS flag is set, prefer directory servers
   * that we can use with BEGINDIR.
   */
 -static routerstatus_t *
 +static const routerstatus_t *
  router_pick_directory_server_impl(authority_type_t type, int flags)
  {
+   or_options_t *options = get_options();
 -  routerstatus_t *result;
 +  const node_t *result;
    smartlist_t *direct, *tunnel;
    smartlist_t *trusted_direct, *trusted_tunnel;
    smartlist_t *overloaded_direct, *overloaded_tunnel;
@@@ -1096,19 -1095,16 +1100,20 @@@
    overloaded_tunnel = smartlist_create();
  
    /* Find all the running dirservers we know about. */
 -  SMARTLIST_FOREACH_BEGIN(consensus->routerstatus_list, routerstatus_t *,
 -                          status) {
 +  SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), const node_t *, node) {
      int is_trusted;
 -    int is_overloaded = status->last_dir_503_at + DIR_503_TIMEOUT > now;
 +    int is_overloaded;
      tor_addr_t addr;
 -    if (!status->is_running || !status->dir_port || !status->is_valid)
 +    const routerstatus_t *status = node->rs;
++    const country_t country = node->country;
 +    if (!status)
        continue;
 -    if (status->is_bad_directory)
 +
 +    if (!node->is_running || !status->dir_port || !node->is_valid)
 +      continue;
 +    if (node->is_bad_directory)
        continue;
 -    if (requireother && router_digest_is_me(status->identity_digest))
 +    if (requireother && router_digest_is_me(node->identity))
        continue;
      if (type & V3_AUTHORITY) {
        if (!(status->version_supports_v3_dir ||
@@@ -1116,17 -1112,20 +1121,23 @@@
                                                V3_AUTHORITY)))
          continue;
      }
 -    is_trusted = router_digest_is_trusted_dir(status->identity_digest);
 -    if ((type & V2_AUTHORITY) && !(status->is_v2_dir || is_trusted))
 +    is_trusted = router_digest_is_trusted_dir(node->identity);
 +    if ((type & V2_AUTHORITY) && !(node->rs->is_v2_dir || is_trusted))
        continue;
      if ((type & EXTRAINFO_CACHE) &&
 -        !router_supports_extrainfo(status->identity_digest, 0))
 +        !router_supports_extrainfo(node->identity, 0))
        continue;
+     if (try_excluding && options->ExcludeNodes &&
 -        routerset_contains_routerstatus(options->ExcludeNodes, status)) {
++        routerset_contains_routerstatus(options->ExcludeNodes, status,
++                                        country)) {
+       ++n_excluded;
+       continue;
+     }
  
      /* XXXX IP6 proposal 118 */
 -    tor_addr_from_ipv4h(&addr, status->addr);
 +    tor_addr_from_ipv4h(&addr, node->rs->addr);
 +
 +    is_overloaded = status->last_dir_503_at + DIR_503_TIMEOUT > now;
  
      if (prefer_tunnel &&
          status->version_supports_begindir &&
@@@ -1165,7 -1164,16 +1176,16 @@@
    smartlist_free(trusted_tunnel);
    smartlist_free(overloaded_direct);
    smartlist_free(overloaded_tunnel);
+ 
+   if (result == NULL && try_excluding && !options->StrictNodes && n_excluded) {
+     /* If we got no result, and we are excluding nodes, and StrictNodes is
+      * not set, try again without excluding nodes. */
+     try_excluding = 0;
+     n_excluded = 0;
+     goto retry_without_exclude;
+   }
+ 
 -  return result;
 +  return result ? result->rs : NULL;
  }
  
  /** Choose randomly from among the trusted dirservers that are up.  Flags
@@@ -1175,17 -1183,18 +1195,19 @@@ static const routerstatus_t 
  router_pick_trusteddirserver_impl(authority_type_t type, int flags,
                                    int *n_busy_out)
  {
+   or_options_t *options = get_options();
    smartlist_t *direct, *tunnel;
    smartlist_t *overloaded_direct, *overloaded_tunnel;
 -  routerinfo_t *me = router_get_my_routerinfo();
 -  routerstatus_t *result;
 +  const routerinfo_t *me = router_get_my_routerinfo();
 +  const routerstatus_t *result;
    time_t now = time(NULL);
    const int requireother = ! (flags & PDS_ALLOW_SELF);
    const int fascistfirewall = ! (flags & PDS_IGNORE_FASCISTFIREWALL);
    const int prefer_tunnel = (flags & _PDS_PREFER_TUNNELED_DIR_CONNS);
    const int no_serverdesc_fetching =(flags & PDS_NO_EXISTING_SERVERDESC_FETCH);
 +  const int no_microdesc_fetching =(flags & PDS_NO_EXISTING_MICRODESC_FETCH);
    int n_busy = 0;
+   int try_excluding = 1, n_excluded = 0;
  
    if (!trusted_dir_servers)
      return NULL;
@@@ -1208,6 -1219,12 +1232,12 @@@
          continue;
        if (requireother && me && router_digest_is_me(d->digest))
            continue;
+       if (try_excluding && options->ExcludeNodes &&
+           routerset_contains_routerstatus(options->ExcludeNodes,
 -                                          &d->fake_status)) {
++                                          &d->fake_status, -1)) {
+         ++n_excluded;
+         continue;
+       }
  
        /* XXXX IP6 proposal 118 */
        tor_addr_from_ipv4h(&addr, d->addr);
@@@ -1364,45 -1380,21 +1403,45 @@@ nodelist_add_node_family(smartlist_t *s
    }
  
    /* If the user declared any families locally, honor those too. */
 -  for (cl = options->NodeFamilies; cl; cl = cl->next) {
 -    if (router_nickname_is_in_list(router, cl->value)) {
 -      add_nickname_list_to_smartlist(sl, cl->value, 0);
 -    }
 +  if (options->NodeFamilySets) {
 +    SMARTLIST_FOREACH(options->NodeFamilySets, const routerset_t *, rs, {
 +      if (routerset_contains_node(rs, node)) {
-         routerset_get_all_nodes(sl, rs, 0);
++        routerset_get_all_nodes(sl, rs, NULL, 0);
 +      }
 +    });
 +  }
 +}
 +
 +/** Given a <b>router</b>, add every node_t in its family to <b>sl</b>.
 + *
 + * Note the type mismatch: This function takes a routerinfo, but adds nodes
 + * to the smartlist!
 + */
 +static void
 +routerlist_add_nodes_in_family(smartlist_t *sl, const routerinfo_t *router)
 +{
 +  /* XXXX MOVE ? */
 +  node_t fake_node;
 +  const node_t *node = node_get_by_id(router->cache_info.identity_digest);;
 +  if (node == NULL) {
 +    memset(&fake_node, 0, sizeof(fake_node));
 +    fake_node.ri = (routerinfo_t *)router;
 +    memcpy(fake_node.identity, router->cache_info.identity_digest, DIGEST_LEN);
 +    node = &fake_node;
    }
 +  nodelist_add_node_family(sl, node);
  }
  
 -/** Return true iff r is named by some nickname in <b>lst</b>. */
 +/** Return true iff <b>node</b> is named by some nickname in <b>lst</b>. */
  static INLINE int
 -router_in_nickname_smartlist(smartlist_t *lst, routerinfo_t *r)
 +node_in_nickname_smartlist(const smartlist_t *lst, const node_t *node)
  {
 +  /* XXXX MOVE */
    if (!lst) return 0;
 -  SMARTLIST_FOREACH(lst, const char *, name,
 -    if (router_nickname_matches(r, name))
 -      return 1;);
 +  SMARTLIST_FOREACH(lst, const char *, name, {
 +    if (node_nickname_matches(node, name))
 +      return 1;
 +  });
    return 0;
  }
  
@@@ -1512,10 -1538,12 +1551,12 @@@ routerlist_find_my_routerinfo(void
  /** Find a router that's up, that has this IP address, and
   * that allows exit to this address:port, or return NULL if there
   * isn't a good one.
+  * Don't exit enclave to excluded relays -- it wouldn't actually
+  * hurt anything, but this way there are fewer confused users.
   */
 -routerinfo_t *
 +const node_t *
  router_find_exact_exit_enclave(const char *address, uint16_t port)
 -{
 +{/*XXXX MOVE*/
    uint32_t addr;
    struct in_addr in;
    tor_addr_t a;
@@@ -1526,12 -1555,14 +1568,13 @@@
  
    tor_addr_from_ipv4h(&a, addr);
  
 -  SMARTLIST_FOREACH(routerlist->routers, routerinfo_t *, router,
 -  {
 -    if (router->addr == addr &&
 -        router->is_running &&
 -        compare_tor_addr_to_addr_policy(&a, port, router->exit_policy) ==
 +  SMARTLIST_FOREACH(nodelist_get_list(), const node_t *, node, {
 +    if (node_get_addr_ipv4h(node) == addr &&
 +        node->is_running &&
 +        compare_tor_addr_to_node_policy(&a, port, node) ==
-           ADDR_POLICY_ACCEPTED)
+           ADDR_POLICY_ACCEPTED &&
 -        !routerset_contains_router(options->_ExcludeExitNodesUnion, router))
 -      return router;
++        !routerset_contains_node(options->_ExcludeExitNodesUnion, node))
 +      return node;
    });
    return NULL;
  }
@@@ -5564,55 -5552,50 +5607,59 @@@ routerset_contains_routerstatus(const r
                              rs->or_port,
                              rs->nickname,
                              rs->identity_digest,
 -                            rs->is_named,
 -                            -1);
 +                            country);
 +}
 +
 +/** Return true iff <b>node</b> is in <b>set</b>. */
 +int
 +routerset_contains_node(const routerset_t *set, const node_t *node)
 +{
 +  if (node->rs)
 +    return routerset_contains_routerstatus(set, node->rs, node->country);
 +  else if (node->ri)
 +    return routerset_contains_router(set, node->ri, node->country);
 +  else
 +    return 0;
  }
  
 -/** Add every known routerinfo_t that is a member of <b>routerset</b> to
 +/** Add every known node_t that is a member of <b>routerset</b> to
-  * <b>out</b>.  If <b>running_only</b>, only add the running ones. */
+  * <b>out</b>, but never add any that are part of <b>excludeset</b>.
+  * If <b>running_only</b>, only add the running ones. */
  void
 -routerset_get_all_routers(smartlist_t *out, const routerset_t *routerset,
 -                          const routerset_t *excludeset, int running_only)
 -{
 +routerset_get_all_nodes(smartlist_t *out, const routerset_t *routerset,
-                         int running_only)
++                        const routerset_t *excludeset, int running_only)
 +{ /* XXXX MOVE */
    tor_assert(out);
    if (!routerset || !routerset->list)
      return;
 -  if (!warned_nicknames)
 -    warned_nicknames = smartlist_create();
 -  if (routerset_is_list(routerset)) {
  
 +  if (routerset_is_list(routerset)) {
      /* No routers are specified by type; all are given by name or digest.
-      * we can do a lookup in O(len(list)). */
+      * we can do a lookup in O(len(routerset)). */
      SMARTLIST_FOREACH(routerset->list, const char *, name, {
 -        routerinfo_t *router = router_get_by_nickname(name, 1);
 -        if (router) {
 -          if (!running_only || router->is_running)
 -            if (!routerset_contains_router(excludeset, router))
 -              smartlist_add(out, router);
 +        const node_t *node = node_get_by_nickname(name, 1);
 +        if (node) {
 +          if (!running_only || node->is_running)
-             smartlist_add(out, (void*)node);
++            if (!routerset_contains_node(excludeset, node))
++              smartlist_add(out, (void*)node);
          }
      });
    } else {
      /* We need to iterate over the routerlist to get all the ones of the
       * right kind. */
 -    routerlist_t *rl = router_get_routerlist();
 -    SMARTLIST_FOREACH(rl->routers, routerinfo_t *, router, {
 -        if (running_only && !router->is_running)
 +    smartlist_t *nodes = nodelist_get_list();
 +    SMARTLIST_FOREACH(nodes, const node_t *, node, {
 +        if (running_only && !node->is_running)
            continue;
-         if (routerset_contains_node(routerset, node))
 -        if (routerset_contains_router(routerset, router) &&
 -            !routerset_contains_router(excludeset, router))
 -          smartlist_add(out, router);
++        if (routerset_contains_node(routerset, node) &&
++            !routerset_contains_node(excludeset, node))
 +          smartlist_add(out, (void*)node);
      });
    }
  }
  
+ #if 0
 -/** Add to <b>target</b> every routerinfo_t from <b>source</b> except:
 +/** Add to <b>target</b> every node_t from <b>source</b> except:
   *
   * 1) Don't add it if <b>include</b> is non-empty and the relay isn't in
   * <b>include</b>; and
@@@ -5642,11 -5625,12 +5689,12 @@@ routersets_get_node_disjunction(smartli
      }
    });
  }
+ #endif
  
 -/** Remove every routerinfo_t from <b>lst</b> that is in <b>routerset</b>. */
 +/** Remove every node_t from <b>lst</b> that is in <b>routerset</b>. */
  void
 -routerset_subtract_routers(smartlist_t *lst, const routerset_t *routerset)
 -{
 +routerset_subtract_nodes(smartlist_t *lst, const routerset_t *routerset)
 +{ /*XXXX MOVE ? */
    tor_assert(lst);
    if (!routerset)
      return;
diff --cc src/or/routerlist.h
index bb7a098,fec1870..794fc0c
--- a/src/or/routerlist.h
+++ b/src/or/routerlist.h
@@@ -169,25 -167,28 +169,31 @@@ int routerset_parse(routerset_t *target
  void routerset_union(routerset_t *target, const routerset_t *source);
  int routerset_is_list(const routerset_t *set);
  int routerset_needs_geoip(const routerset_t *set);
+ int routerset_is_empty(const routerset_t *set);
 -int routerset_contains_router(const routerset_t *set, routerinfo_t *ri);
 +int routerset_contains_router(const routerset_t *set, const routerinfo_t *ri,
 +                              country_t country);
  int routerset_contains_routerstatus(const routerset_t *set,
 -                                    routerstatus_t *rs);
 +                                    const routerstatus_t *rs,
 +                                    country_t country);
  int routerset_contains_extendinfo(const routerset_t *set,
                                    const extend_info_t *ei);
 -void routerset_get_all_routers(smartlist_t *out, const routerset_t *routerset,
 -                               const routerset_t *excludeset,
 -                               int running_only);
++
 +int routerset_contains_node(const routerset_t *set, const node_t *node);
 +void routerset_get_all_nodes(smartlist_t *out, const routerset_t *routerset,
++                             const routerset_t *excludeset,
 +                             int running_only);
+ #if 0
 -void routersets_get_disjunction(smartlist_t *target, const smartlist_t *source,
 +void routersets_get_node_disjunction(smartlist_t *target,
 +                                const smartlist_t *source,
                                  const routerset_t *include,
                                  const routerset_t *exclude, int running_only);
+ #endif
 -void routerset_subtract_routers(smartlist_t *out,
 +void routerset_subtract_nodes(smartlist_t *out,
-                               const routerset_t *routerset);
+                                 const routerset_t *routerset);
++
  char *routerset_to_string(const routerset_t *routerset);
 -void routerset_refresh_countries(routerset_t *target);
  int routerset_equal(const routerset_t *old, const routerset_t *new);
  void routerset_free(routerset_t *routerset);
 -void routerinfo_set_country(routerinfo_t *ri);
 -void routerlist_refresh_countries(void);
  void refresh_all_country_info(void);
  
  int hid_serv_get_responsible_directories(smartlist_t *responsible_dirs,



More information about the tor-commits mailing list