[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[or-cvs] [tor/master 06/15] Implement node-based router family code



Author: Nick Mathewson <nickm@xxxxxxxxxxxxxx>
Date: Thu, 30 Sep 2010 18:25:25 -0400
Subject: Implement node-based router family code
Commit: f9ea242acabcaec0ab0fbd0de5e9999dfcdb0193

Also, make the NodeFamily option into a list of routersets.  This
lets us git rid of router_in_nickname_list (or whatever it was
called) without porting it to work with nodes, and also lets people
specify country codes and IP ranges in NodeFamily
---
 doc/nodefamily_routerset |    4 +
 doc/tor.1.txt            |    3 +-
 src/or/config.c          |   23 ++++++-
 src/or/nodelist.c        |   13 ++++
 src/or/nodelist.h        |    1 +
 src/or/or.h              |    3 +-
 src/or/routerlist.c      |  180 +++++++++++++++++++++++++++------------------
 7 files changed, 152 insertions(+), 75 deletions(-)
 create mode 100644 doc/nodefamily_routerset

diff --git a/doc/nodefamily_routerset b/doc/nodefamily_routerset
new file mode 100644
index 0000000..0af62e1
--- /dev/null
+++ b/doc/nodefamily_routerset
@@ -0,0 +1,4 @@
+  o Minor features
+    - The NodeFamily option -- which let you declare that you want to
+      consider nodes to be part of a family whether they list themselves
+      that way or not -- now allows IP address ranges and country codes.
diff --git a/doc/tor.1.txt b/doc/tor.1.txt
index 42eed6e..90a52fe 100644
--- a/doc/tor.1.txt
+++ b/doc/tor.1.txt
@@ -571,7 +571,8 @@ The following options are useful only for clients (that is, if
     constitute a "family" of similar or co-administered servers, so never use
     any two of them in the same circuit. Defining a NodeFamily is only needed
     when a server doesn't list the family itself (with MyFamily). This option
-    can be used multiple times.
+    can be used multiple times.  In addition to nodes, you can also list
+    IP address and ranges and country codes in {curly braces}.
 
 **EnforceDistinctSubnets** **0**|**1**::
     If 1, Tor will not put two servers whose IP addresses are "too close" on
diff --git a/src/or/config.c b/src/or/config.c
index 4f70771..b438626 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -691,6 +691,11 @@ or_options_free(or_options_t *options)
     return;
 
   routerset_free(options->_ExcludeExitNodesUnion);
+  if (options->NodeFamilySets) {
+    SMARTLIST_FOREACH(options->NodeFamilySets, routerset_t *,
+                      rs, routerset_free(rs));
+    smartlist_free(options->NodeFamilySets);
+  }
   config_free(&options_format, options);
 }
 
@@ -3084,6 +3089,18 @@ options_validate(or_options_t *old_options, or_options_t *options,
     routerset_union(options->_ExcludeExitNodesUnion,options->ExcludeNodes);
   }
 
+  if (options->NodeFamilies) {
+    options->NodeFamilySets = smartlist_create();
+    for (cl = options->NodeFamilies; cl; cl = cl->next) {
+      routerset_t *rs = routerset_new();
+      if (routerset_parse(rs, cl->value, cl->key) == 0) {
+        smartlist_add(options->NodeFamilySets, rs);
+      } else {
+        routerset_free(rs);
+      }
+    }
+  }
+
   if (options->ExcludeNodes && options->StrictNodes) {
     COMPLAIN("You have asked to exclude certain relays from all positions "
              "in your circuits. Expect hidden services and other Tor "
@@ -3549,8 +3566,12 @@ options_validate(or_options_t *old_options, or_options_t *options,
   if (check_nickname_list(options->MyFamily, "MyFamily", msg))
     return -1;
   for (cl = options->NodeFamilies; cl; cl = cl->next) {
-    if (check_nickname_list(cl->value, "NodeFamily", msg))
+    routerset_t *rs = routerset_new();
+    if (routerset_parse(rs, cl->value, cl->key)) {
+      routerset_free(rs);
       return -1;
+    }
+    routerset_free(rs);
   }
 
   if (validate_addr_policies(options, msg) < 0)
diff --git a/src/or/nodelist.c b/src/or/nodelist.c
index dd83abf..7c03698 100644
--- a/src/or/nodelist.c
+++ b/src/or/nodelist.c
@@ -698,6 +698,19 @@ node_is_me(const node_t *node)
   return router_digest_is_me(node->identity);
 }
 
+/** Return <b>node</b> declared family (as a list of names), or NULL if
+ * the node didn't declare a family. */
+const smartlist_t *
+node_get_declared_family(const node_t *node)
+{
+  if (node->ri && node->ri->declared_family)
+    return node->ri->declared_family;
+  else if (node->md && node->md->family)
+    return node->md->family;
+  else
+    return NULL;
+}
+
 /* KILLTHIS XXXX NM -- it's a dummy to keep UNIMPLEMENTED_NODELIST()
  * working */
 int unimplemented_nodelist_truth = 1;
diff --git a/src/or/nodelist.h b/src/or/nodelist.h
index 3dceb75..cb78366 100644
--- a/src/or/nodelist.h
+++ b/src/or/nodelist.h
@@ -45,6 +45,7 @@ const char *node_get_platform(const node_t *node);
 void node_get_address_string(const node_t *node, char *cp, size_t len);
 long node_get_declared_uptime(const node_t *node);
 time_t node_get_published_on(const node_t *node);
+const smartlist_t *node_get_declared_family(const node_t *node);
 
 smartlist_t *nodelist_get_list(void);
 
diff --git a/src/or/or.h b/src/or/or.h
index 670cf7d..ac96347 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -2725,7 +2725,8 @@ typedef struct {
 
   char *MyFamily; /**< Declared family for this OR. */
   config_line_t *NodeFamilies; /**< List of config lines for
-                                       * node families */
+                                * node families */
+  smartlist_t *NodeFamilySets; /**< List of parsed NodeFamilies values. */
   config_line_t *AuthDirBadDir; /**< Address policy for descriptors to
                                  * mark as bad dir mirrors. */
   config_line_t *AuthDirBadExit; /**< Address policy for descriptors to
diff --git a/src/or/routerlist.c b/src/or/routerlist.c
index a082ff4..73657fc 100644
--- a/src/or/routerlist.c
+++ b/src/or/routerlist.c
@@ -46,6 +46,8 @@ static const routerstatus_t *router_pick_trusteddirserver_impl(
 static void mark_all_trusteddirservers_up(void);
 static int router_nickname_matches(const routerinfo_t *router,
                                    const char *nickname);
+static int node_nickname_matches(const node_t *router,
+                                 const char *nickname);
 static void trusted_dir_server_free(trusted_dir_server_t *ds);
 static int signed_desc_digest_is_recognized(signed_descriptor_t *desc);
 static void update_router_have_minimum_dir_info(void);
@@ -1300,72 +1302,70 @@ router_reset_status_download_failures(void)
   mark_all_trusteddirservers_up();
 }
 
-/** Return true iff router1 and router2 have the same /16 network. */
+/** Return true iff router1 and router2 have similar enough network addresses
+ * that we should treat them as being in the same family */
 static INLINE int
-routers_in_same_network_family(const routerinfo_t *r1, const routerinfo_t *r2)
+addrs_in_same_network_family(const tor_addr_t *a1,
+                             const tor_addr_t *a2)
 {
-  return (r1->addr & 0xffff0000) == (r2->addr & 0xffff0000);
+  /* XXXX MOVE ? */
+  return 0 == tor_addr_compare_masked(a1, a2, 16, CMP_SEMANTIC);
 }
 
-#if 0
-/** Look through the routerlist and identify routers that
- * advertise the same /16 network address as <b>router</b>.
- * Add each of them to <b>sl</b>.
- */
-static void
-routerlist_add_network_family(smartlist_t *sl, const routerinfo_t *router)
-{
-  SMARTLIST_FOREACH(routerlist->routers, routerinfo_t *, r,
-  {
-    if (router != r && routers_in_same_network_family(router, r))
-      smartlist_add(sl, r);
-  });
-}
-#endif
-
 /** Add all the family of <b>router</b> to the smartlist <b>sl</b>.
  * This is used to make sure we don't pick siblings in a single path,
  * or pick more than one relay from a family for our entry guard list.
  */
 void
-nodelist_add_node_family(smartlist_t *sl, const node_t *router)
+nodelist_add_node_family(smartlist_t *sl, const node_t *node)
 {
   /* XXXX MOVE */
-#if 0
-  const routerinfo_t *r;
-  config_line_t *cl;
+  const smartlist_t *all_nodes = nodelist_get_list();
+  const smartlist_t *declared_family = node_get_declared_family(node);
   or_options_t *options = get_options();
 
-  /* First, add any routers with similar network addresses. */
-  if (options->EnforceDistinctSubnets)
-    routerlist_add_network_family(sl, router);
+  /* First, add any nodes with similar network addresses. */
+  if (options->EnforceDistinctSubnets) {
+    tor_addr_t node_addr;
+    node_get_addr(node, &node_addr);
 
-  if (router->declared_family) {
-    /* Add every r such that router declares familyness with r, and r
+    SMARTLIST_FOREACH_BEGIN(all_nodes, const node_t *, node2) {
+      tor_addr_t a;
+      node_get_addr(node2, &a);
+      if (addrs_in_same_network_family(&a, &node_addr))
+        smartlist_add(sl, (void*)node2);
+    } SMARTLIST_FOREACH_END(node);
+  }
+
+  /* Now, add all nodes in the declared_family of this node, if they
+   * also declare this node to be in their family. */
+  if (declared_family) {
+    /* Add every r such that router declares familyness with node, and node
      * declares familyhood with router. */
-    SMARTLIST_FOREACH_BEGIN(router->declared_family, const char *, n) {
-        if (!(r = router_get_by_nickname(n, 0)))
-          continue;
-        if (!r->declared_family)
-          continue;
-        SMARTLIST_FOREACH(r->declared_family, const char *, n2,
-          {
-            if (router_nickname_matches(router, n2))
-              smartlist_add(sl, (void*)r);
-          });
-    } SMARTLIST_FOREACH_END(n);
+    SMARTLIST_FOREACH_BEGIN(declared_family, const char *, name) {
+      const node_t *node2;
+      const smartlist_t *family2;
+      if (!(node2 = node_get_by_nickname(name, 0)))
+        continue;
+      if (!(family2 = node_get_declared_family(node2)))
+        continue;
+      SMARTLIST_FOREACH(family2, const char *, name2, {
+          if (node_nickname_matches(node, name2)) {
+            smartlist_add(sl, (void*)node2);
+            break;
+          }
+        });
+    } SMARTLIST_FOREACH_END(name);
   }
 
   /* 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);
+      }
+    });
   }
-#endif
-  (void)sl;
-  (void)router;
-  UNIMPLEMENTED_NODELIST();
 }
 
 /** Given a <b>router</b>, add every node_t in its family to <b>sl</b>.
@@ -1376,19 +1376,28 @@ nodelist_add_node_family(smartlist_t *sl, const node_t *router)
 static void
 routerlist_add_nodes_in_family(smartlist_t *sl, const routerinfo_t *router)
 {
-  (void)router;
-  (void)sl;
-  UNIMPLEMENTED_NODELIST();
+  /* 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, &fake_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, const 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;
 }
 
@@ -1397,27 +1406,38 @@ router_in_nickname_smartlist(smartlist_t *lst, const routerinfo_t *r)
 int
 nodes_in_same_family(const node_t *node1, const node_t *node2)
 {
-#if 0
+  /* XXXX MOVE */
   or_options_t *options = get_options();
-  config_line_t *cl;
 
-  if (options->EnforceDistinctSubnets &&
-      nodes_in_same_network_family(node1,node2))
-    return 1;
-
-  if (router_in_nickname_smartlist(r1->declared_family, r2) &&
-      router_in_nickname_smartlist(r2->declared_family, r1))
-    return 1;
+  /* Are they in the same family because of their addresses? */
+  if (options->EnforceDistinctSubnets) {
+    tor_addr_t a1, a2;
+    node_get_addr(node1, &a1);
+    node_get_addr(node2, &a2);
+    if (addrs_in_same_network_family(&a1, &a2))
+      return 1;
+  }
 
-  for (cl = options->NodeFamilies; cl; cl = cl->next) {
-    if (router_nickname_is_in_list(r1, cl->value) &&
-        router_nickname_is_in_list(r2, cl->value))
+  /* Are they in the same family because the agree they are? */
+  {
+    const smartlist_t *f1, *f2;
+    f1 = node_get_declared_family(node1);
+    f2 = node_get_declared_family(node2);
+    if (f1 && f2 &&
+        node_in_nickname_smartlist(f1, node2) &&
+        node_in_nickname_smartlist(f2, node1))
       return 1;
   }
-#endif
-  (void)node1;
-  (void)node2;
-  UNIMPLEMENTED_NODELIST();
+
+  /* Are they in the same option because the user says they are? */
+  if (options->NodeFamilySets) {
+    SMARTLIST_FOREACH(options->NodeFamilySets, const routerset_t *, rs, {
+        if (routerset_contains_node(rs, node1) &&
+            routerset_contains_node(rs, node2))
+          return 1;
+      });
+  }
+
   return 0;
 }
 
@@ -1431,7 +1451,7 @@ nodes_in_same_family(const node_t *node1, const node_t *node2)
 static void
 add_nickname_list_to_smartlist(smartlist_t *sl, const char *list,
                                int must_be_running)
-{ /*XXXX MOVE */
+{ /*XXXX MOVE or Kill. */
   /*XXXX this is only used in one place. Can we kill it?*/
   const node_t *node;
   const routerinfo_t *router;
@@ -2301,6 +2321,22 @@ router_nickname_matches(const routerinfo_t *router, const char *nickname)
   return router_hex_digest_matches(router, nickname);
 }
 
+/** Return true if <b>node</b>'s nickname matches <b>nickname</b>
+ * (case-insensitive), or if <b>node's</b> identity key digest
+ * matches a hexadecimal value stored in <b>nickname</b>.  Return
+ * false otherwise. */
+static int
+node_nickname_matches(const node_t *node, const char *nickname)
+{
+  const char *n = node_get_nickname(node);
+  if (n && nickname[0]!='$' && !strcasecmp(n, nickname))
+    return 1;
+  return hex_digest_nickname_matches(nickname,
+                                     node->identity,
+                                     n,
+                                     node_is_named(node));
+}
+
 /** Return the router in our routerlist whose (case-insensitive)
  * nickname or (case-sensitive) hexadecimal key digest is
  * <b>nickname</b>.  Return NULL if no such router is known.
-- 
1.7.1