[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