Browse Source

Fallbacks: accept relays that are a fuzzy match to the whitelist

If a relay matches at least one fingerprint, IPv4 address, or IPv6
address in the fallback whitelist, it can become a fallback. This
reduces the work required to keep the list up to date.

Closes ticket 28768.
teor 6 years ago
parent
commit
6bc5c06dc2
3 changed files with 48 additions and 14 deletions
  1. 6 0
      changes/ticket24838
  2. 14 12
      scripts/maint/fallback.whitelist
  3. 28 2
      scripts/maint/updateFallbackDirs.py

+ 6 - 0
changes/ticket24838

@@ -0,0 +1,6 @@
+  o Minor features (fallback directory mirrors):
+    - Accept relays that are a fuzzy match to a fallback whitelist entry.
+      If a relay matches at least one fingerprint, IPv4 address, or IPv6
+      address in the fallback whitelist, it can become a fallback. This
+      reduces the work required to keep the list up to date.
+      Closes ticket 24838.

+ 14 - 12
scripts/maint/fallback.whitelist

@@ -1,16 +1,18 @@
 # updateFallbackDirs.py directory mirror whitelist
 # updateFallbackDirs.py directory mirror whitelist
-
-# All attributes must match for the directory mirror to be included.
-# If the fallback has an ipv6 key, the whitelist line must also have
-# it, and vice versa, otherwise they don't match.
-
-# To replace this list with the hard-coded fallback list (for testing), use
-# "updateFallbackDirs.py check_existing", or a command similar to:
-#   cat src/app/config/fallback_dirs.inc | grep \" | grep -v weight | \
-#   tr -d '\n' | \
-#   sed 's/"" / /g' | sed 's/""/"/g' | tr \" '\n' | grep -v '^$' \
-#   > scripts/maint/fallback.whitelist
-
+#
+# At least one of these keys must match for a directory mirror to be included
+# in the fallback list:
+#   id
+#   ipv4
+#   ipv6
+# The ports and nickname are ignored. Missing or extra ipv6 addresses
+# are ignored.
+#
+# The latest relay details from Onionoo are included in the generated list.
+#
+# To check the hard-coded fallback list (for testing), use:
+# $ updateFallbackDirs.py check_existing
+#
 # If a relay operator wants their relay to be a FallbackDir,
 # If a relay operator wants their relay to be a FallbackDir,
 # enter the following information here:
 # enter the following information here:
 # <IPv4>:<DirPort> orport=<ORPort> id=<ID> ( ipv6=[<IPv6>]:<IPv6 ORPort> )?
 # <IPv4>:<DirPort> orport=<ORPort> id=<ID> ( ipv6=[<IPv6>]:<IPv6 ORPort> )?

+ 28 - 2
scripts/maint/updateFallbackDirs.py

@@ -1061,14 +1061,40 @@ class Candidate(object):
       return False
       return False
     return True
     return True
 
 
+  def entry_matches_fuzzy(self, entry):
+    """ Is entry a fuzzy match for this fallback?
+        A fallback is a fuzzy match for entry if at least one of these keys
+        in entry matches:
+          id
+          ipv4
+          ipv6 (if present in both the fallback and whitelist)
+        The ports and nickname are ignored. Missing or extra ipv6 addresses
+        are ignored.
+
+        Doesn't log any warning messages. """
+    if self.id_matches(entry['id'], exact=False):
+      return True
+    if self.ipv4_addr_matches(entry['ipv4'], exact=False):
+      return True
+    if entry.has_key('ipv6') and self.has_ipv6():
+      # if both entry and fallback have an ipv6 address, compare them
+      if self.ipv6_addr_matches(entry['ipv6_addr'], exact=False):
+        return True
+    return False
+
   def is_in_whitelist(self, relaylist, exact=False):
   def is_in_whitelist(self, relaylist, exact=False):
     """ If exact is True (existing fallback list), check if this fallback is
     """ If exact is True (existing fallback list), check if this fallback is
         an exact match for any whitelist entry, using entry_matches_exact().
         an exact match for any whitelist entry, using entry_matches_exact().
-    """
+
+        If exact is False (new fallback whitelist), check if this fallback is
+        a fuzzy match for any whitelist entry, using entry_matches_fuzzy(). """
     for entry in relaylist:
     for entry in relaylist:
       if exact:
       if exact:
         if self.entry_matches_exact(entry):
         if self.entry_matches_exact(entry):
           return True
           return True
+      else:
+        if self.entry_matches_fuzzy(entry):
+          return True
     return False
     return False
 
 
   def cw_to_bw_factor(self):
   def cw_to_bw_factor(self):
@@ -2193,7 +2219,7 @@ def process_default():
   logging.getLogger('stem').setLevel(logging.WARNING)
   logging.getLogger('stem').setLevel(logging.WARNING)
   whitelist = {'data': read_from_file(WHITELIST_FILE_NAME, MAX_LIST_FILE_SIZE),
   whitelist = {'data': read_from_file(WHITELIST_FILE_NAME, MAX_LIST_FILE_SIZE),
                'name': WHITELIST_FILE_NAME}
                'name': WHITELIST_FILE_NAME}
-  list_fallbacks(whitelist, exact=True)
+  list_fallbacks(whitelist, exact=False)
 
 
 ## Main Function
 ## Main Function
 def main():
 def main():