]> git.ipfire.org Git - thirdparty/tor.git/commitdiff
nodelist: Additionally use family IDs to decide family membership.
authorNick Mathewson <nickm@torproject.org>
Tue, 11 Feb 2025 14:04:53 +0000 (09:04 -0500)
committerNick Mathewson <nickm@torproject.org>
Thu, 6 Mar 2025 14:41:54 +0000 (09:41 -0500)
This implements the client side of happy families.

changes/happy-families-client [new file with mode: 0644]
src/feature/nodelist/nodelist.c

diff --git a/changes/happy-families-client b/changes/happy-families-client
new file mode 100644 (file)
index 0000000..aeeb666
--- /dev/null
@@ -0,0 +1,4 @@
+  o Major features (client):
+    - Clients now respect "happy families" per proposal 321.
+      This feature will eventually allow a much more compact representation
+      for relay families, for a significant savings in directory download size.
index 8f0f46d132f0c4330abb0f0b005f1f769330d3f7..889140b4084bbec85f221f86b087104d104d4d9f 100644 (file)
@@ -2171,6 +2171,38 @@ node_has_declared_family_list(const node_t *node)
   return false;
 }
 
+/**
+ * Return the listed family IDs of `a`, if it has any.
+ */
+static const smartlist_t *
+node_get_family_ids(const node_t *node)
+{
+  if (node->ri && node->ri->family_ids) {
+    return node->ri->family_ids;
+  } else if (node->md && node->md->family_ids) {
+    return node->md->family_ids;
+  } else {
+    return NULL;
+  }
+}
+
+/**
+ * Return true iff `a` and `b` have any family ID in common.
+ **/
+static bool
+nodes_have_common_family_id(const node_t *a, const node_t *b)
+{
+  const smartlist_t *ids_a = node_get_family_ids(a);
+  const smartlist_t *ids_b = node_get_family_ids(b);
+  if (ids_a == NULL || ids_b == NULL)
+    return false;
+  SMARTLIST_FOREACH(ids_a, const char *, id, {
+      if (smartlist_contains_string(ids_b, id))
+        return true;
+    });
+  return false;
+}
+
 /**
  * Add to <b>out</b> every node_t that is listed by <b>node</b> as being in
  * its family.  (Note that these nodes are not in node's family unless they
@@ -2217,12 +2249,20 @@ nodes_in_same_family(const node_t *node1, const node_t *node2)
       return 1;
   }
 
-  /* Are they in the same family because the agree they are? */
-  if (node_family_list_contains(node1, node2) &&
+  /* Are they in the same family because they agree they are? */
+  if (use_family_lists &&
+      node_family_list_contains(node1, node2) &&
       node_family_list_contains(node2, node1)) {
     return 1;
   }
 
+  /* Are they in the same family because they have a common
+   * verified family ID? */
+  if (use_family_ids &&
+      nodes_have_common_family_id(node1, node2)) {
+    return 1;
+  }
+
   /* Are they in the same family because the user says they are? */
   if (options->NodeFamilySets) {
     SMARTLIST_FOREACH(options->NodeFamilySets, const routerset_t *, rs, {
@@ -2279,7 +2319,8 @@ nodelist_add_node_and_family(smartlist_t *sl, const node_t *node)
 
   /* Now, add all nodes in the declared family of this node, if they
    * also declare this node to be in their family. */
-  if (node_has_declared_family_list(node)) {
+  if (use_family_lists &&
+      node_has_declared_family_list(node)) {
     smartlist_t *declared_family = smartlist_new();
     node_lookup_declared_family_list(declared_family, node);
 
@@ -2293,6 +2334,16 @@ nodelist_add_node_and_family(smartlist_t *sl, const node_t *node)
     smartlist_free(declared_family);
   }
 
+  /* Now add all the nodes that share a verified family ID with this node. */
+  if (use_family_ids &&
+      node_get_family_ids(node)) {
+    SMARTLIST_FOREACH(all_nodes, const node_t *, node2, {
+        if (nodes_have_common_family_id(node, node2)) {
+          smartlist_add(sl, (void *)node2);
+        }
+      });
+  }
+
   /* If the user declared any families locally, honor those too. */
   if (options->NodeFamilySets) {
     SMARTLIST_FOREACH(options->NodeFamilySets, const routerset_t *, rs, {