[tor-commits] [chutney/master] Stop waiting a set time for microdescriptors

nickm at torproject.org nickm at torproject.org
Wed Jun 3 18:39:55 UTC 2020


commit faf96c28b4c5ccf38cceed33beebf0db85a01b79
Author: teor <teor at riseup.net>
Date:   Mon May 18 13:14:26 2020 +1000

    Stop waiting a set time for microdescriptors
---
 lib/chutney/TorNet.py | 94 +++++++++++++--------------------------------------
 1 file changed, 23 insertions(+), 71 deletions(-)

diff --git a/lib/chutney/TorNet.py b/lib/chutney/TorNet.py
index 1d9f7c7..f6e44b4 100644
--- a/lib/chutney/TorNet.py
+++ b/lib/chutney/TorNet.py
@@ -52,7 +52,6 @@ def getenv_type(env_var, default, type_, type_name=None):
     """
        Return the value of the environment variable 'envar' as type_,
        or 'default' if no such variable exists.
-
        Raise ValueError using type_name if the environment variable is set,
        but type_() raises a ValueError on its value. (If type_name is None
        or empty, the ValueError uses type_'s string representation instead.)
@@ -73,7 +72,6 @@ def getenv_int(env_var, default):
     """
        Return the value of the environment variable 'envar' as an int,
        or 'default' if no such variable exists.
-
        Raise ValueError if the environment variable is set, but is not an int.
     """
     return getenv_type(env_var, default, int, type_name='an int')
@@ -82,9 +80,7 @@ def getenv_bool(env_var, default):
     """
        Return the value of the environment variable 'envar' as a bool,
        or 'default' if no such variable exists.
-
        Unlike bool(), converts 0, "False", and "No" to False.
-
        Raise ValueError if the environment variable is set, but is not a bool.
     """
     try:
@@ -101,11 +97,9 @@ def getenv_bool(env_var, default):
 def mkdir_p(d, mode=448):
     """Create directory 'd' and all of its parents as needed.  Unlike
        os.makedirs, does not give an error if d already exists.
-
        448 is the decimal representation of the octal number 0700. Since
        python2 only supports 0700 and python3 only supports 0o700, we can use
        neither.
-
        Note that python2 and python3 differ in how they create the
        permissions for the intermediate directories.  In python3, 'mode'
        only sets the mode for the last directory created.
@@ -141,15 +135,12 @@ def get_absolute_net_path():
     """
        Returns the absolute path of the "net" directory that chutney should
        use to store "node*" directories containing torrcs and tor runtime data.
-
        If the CHUTNEY_DATA_DIR environmental variable is an absolute path, it
        is returned unmodified, regardless of whether the path actually exists.
        (Chutney creates any directories that do not exist.)
-
        Otherwise, if it is a relative path, and there is an existing directory
        with that name in the directory containing the chutney executable
        script, return that path (this check exists for legacy reasons).
-
        Finally, return the path relative to the current working directory,
        regardless of whether the path actually exists.
     """
@@ -179,8 +170,6 @@ def get_absolute_nodes_path():
 
        This path is also used as a prefix for the unique nodes directory
        names.
-
-       See get_new_absolute_nodes_path() for more details.
     """
     return os.path.join(get_absolute_net_path(), 'nodes')
 
@@ -188,10 +177,8 @@ def get_new_absolute_nodes_path(now=time.time()):
     """
        Returns the absolute path of a unique "nodes*" directory that chutney
        should use to store the current network's torrcs and tor runtime data.
-
        The nodes directory suffix is based on the current timestamp,
        incremented if necessary to avoid collisions with existing directories.
-
        (The existing directory check contains known race conditions: running
        multiple simultaneous chutney instances on the same "net" directory is
        not supported. The uniqueness check is only designed to avoid
@@ -233,9 +220,7 @@ def _warnMissingTor(tor_path, cmdline, tor_name="tor"):
 def run_tor(cmdline, exit_on_missing=True):
     """Run the tor command line cmdline, which must start with the path or
        name of a tor binary.
-
        Returns the combined stdout and stderr of the process.
-
        If exit_on_missing is true, warn and exit if the tor binary is missing.
        Otherwise, raise a MissingBinaryException.
     """
@@ -272,7 +257,6 @@ def launch_process(cmdline, tor_name="tor", stdin=None, exit_on_missing=True):
     """Launch the command line cmdline, which must start with the path or
        name of a binary. Use tor_name as the canonical name of the binary in
        logs. Pass stdin to the Popen constructor.
-
        Returns the Popen object for the launched process.
     """
     if tor_name == "tor":
@@ -306,7 +290,6 @@ def run_tor_gencert(cmdline, passphrase):
     """Run the tor-gencert command line cmdline, which must start with the
        path or name of a tor-gencert binary.
        Then send passphrase to the stdin of the process.
-
        Returns the combined stdout and stderr of the process.
     """
     p = launch_process(cmdline,
@@ -377,7 +360,6 @@ def get_tor_modules(tor):
     """Check the list of compile-time modules advertised by the given
        'tor' binary, and return a map from module name to a boolean
        describing whether it is supported.
-
        Unlisted modules are ones that Tor did not treat as compile-time
        optional modules.
     """
@@ -411,7 +393,6 @@ class Node(object):
 
     """A Node represents a Tor node or a set of Tor nodes.  It's created
        in a network configuration file.
-
        This class is responsible for holding the user's selected node
        configuration, and figuring out how the node needs to be
        configured and launched.
@@ -688,7 +669,7 @@ class LocalNodeBuilder(NodeBuilder):
             self._setEd25519Id()
         if self._env['hs']:
             self._makeHiddenServiceDir()
-            
+
     def config(self, net):
         """Called to configure a node: creates a torrc file for it."""
         self._createTorrcFile()
@@ -722,7 +703,6 @@ class LocalNodeBuilder(NodeBuilder):
 
     def _makeHiddenServiceDir(self):
         """Create the hidden service subdirectory for this node.
-
           The directory name is stored under the 'hs_directory' environment
           key. It is combined with the 'dir' data directory key to yield the
           path to the hidden service directory.
@@ -782,7 +762,7 @@ class LocalNodeBuilder(NodeBuilder):
                   .format(repr(" ".join(cmdline)), repr(stdouterr)))
             sys.exit(1)
         self._env['fingerprint'] = fingerprint
-       
+        
     def _setEd25519Id(self):
         """Read the ed25519 identity key for this router, and set up the 'ed25519-id' entry in the Environ"""
         datadir = self._env['dir']
@@ -807,7 +787,7 @@ class LocalNodeBuilder(NodeBuilder):
                     raise ValueError("The current length of the key is {}, which is not matching the expected length of {}".format(CURRENT_ED25519_BASE64_KEY_SIZE, EXPECTED_ED25519_BASE64_KEY_SIZE))
                 else:
                     self._env['ed25519_id'] = ed25519_id
-            
+    
     def _getAltAuthLines(self, hasbridgeauth=False):
         """Return a combination of AlternateDirAuthority,
         and AlternateBridgeAuthority lines for
@@ -907,6 +887,13 @@ class LocalNodeController(NodeController):
         except KeyError:
             return 0
 
+    def getEd25519Id(self):
+        """Return the value of ed25519 key"""
+        try:
+            return self._env['ed25519_id']
+        except KeyError:
+            return None
+
     def getBridgeClient(self):
         """Return the bridge client flag for this node."""
         try:
@@ -967,14 +954,13 @@ class LocalNodeController(NodeController):
     MIN_TOR_VERSION_FOR_MICRODESC_FIX = 'Tor 0.4'
 
     MIN_TIME_FOR_COMPLETE_CONSENSUS = V3_AUTH_VOTING_INTERVAL*1.5
-    MIN_START_TIME_LEGACY = MIN_TIME_FOR_COMPLETE_CONSENSUS + 20
+    MIN_START_TIME_LEGACY = 0
     MIN_START_TIME_RECENT = 0
 
     def getMinStartTime(self):
         """Returns the minimum start time before verifying, regardless of
            whether the network has bootstrapped, or the dir info has been
            distributed.
-
            Based on $CHUTNEY_EXTRA_START_TIME and the tor version.
         """
         # User overrode the dynamic time
@@ -993,13 +979,12 @@ class LocalNodeController(NodeController):
         else:
             return LocalNodeController.MIN_START_TIME_RECENT
 
-    NODE_WAIT_FOR_UNCHECKED_DIR_INFO = 10
+    NODE_WAIT_FOR_UNCHECKED_DIR_INFO = 0
     HS_WAIT_FOR_UNCHECKED_DIR_INFO = V3_AUTH_VOTING_INTERVAL + 10
 
     def getUncheckedDirInfoWaitTime(self):
         """Returns the amount of time to wait before verifying, after the
            network has bootstrapped, and the dir info has been distributed.
-
            Based on whether this node is an onion service.
         """
         if self.getOnionService():
@@ -1255,17 +1240,14 @@ class LocalNodeController(NodeController):
              * a boolean indicating whether this node is a bridge client, and
              * a dict with the expected paths to the consensus files for this
                node.
-
            If v2_dir_paths is True, returns the v3 directory paths.
            Otherwise, returns the bridge status path.
            If v2_dir_paths is True, but this node is not a bridge client or
            bridge authority, returns None. (There are no paths.)
-
            Directory servers usually have both consensus flavours.
            Clients usually have the microdesc consensus, but they may have
            either flavour. (Or both flavours.)
            Only the bridge authority has the bridge networkstatus.
-
            The dict keys are:
              * "ns_cons", "desc", and "desc_new";
              * "md_cons", "md", and "md_new"; and
@@ -1318,9 +1300,7 @@ class LocalNodeController(NodeController):
     def getNodePublishedDirInfoPaths(self):
         """Return a dict of paths to consensus files, where we expect this
            node to be published.
-
            The dict keys are the nicks for each node.
-
            See getNodeCacheDirInfoPaths() for the path data structure, and which
            nodes appear in each type of directory.
         """
@@ -1348,15 +1328,11 @@ class LocalNodeController(NodeController):
 
     def getNodeDirInfoStatusPattern(self, dir_format):
         """Returns a regular expression pattern for finding this node's entry
-           in a dir_format file.
-
-           The microdesc format is not yet implemented, because it requires
-           the ed25519 key. (Or RSA block matching, which is hard.)
+           in a dir_format file and returning None if nickname or ed25519_id key not found.
         """
         nickname = self.getNick()
-        ed25519_id = self._setEd25519Id()
-
-
+        ed25519_key = self.getEd25519Id()
+         
         cons = dir_format in ["ns_cons",
                               "md_cons",
                               "br_status"]
@@ -1379,17 +1355,17 @@ class LocalNodeController(NodeController):
         elif desc:
             return r'^router ' + nickname + " "
         elif md:
-            # Not yet implemented, see #33428
-            return r'^id ed25519 ' + re.escape('ed25519_id') 
-            # r'^id ed25519 " + ed25519_identity (end of line)
-            # needs ed25519-identity from #30642
-            # or the existing keys/ed25519_master_id_public_key
-            #return None
-
+            print(nickname)
+            print(ed25519_key)
+            if ed25519_key:
+                return r'^id ed25519 ' + re.escape(ed25519_key)
+            else:
+                # If there is no ed25519_id, then we can't search for it
+                return None
+            
     def getFileDirInfoStatus(self, dir_format, dir_path):
         """Check dir_path, a directory path used by another node, to see if
            this node is present. The directory path is a dir_format file.
-
            Returns a status 3-tuple containing:
              * an integer status code:
                * negative numbers correspond to errors,
@@ -1435,15 +1411,11 @@ class LocalNodeController(NodeController):
         """Combine the directory statuses in dir_status, if their keys
            appear in status_key_list. Keys may be directory formats, or
            node nicks.
-
            If best is True, choose the best status, otherwise, choose the
            worst status.
-
            If ignore_missing is True, ignore missing statuses, if there is any
            other status available.
-
            If statuses are equal, combine their format sets.
-
            Returns None if the status list is empty.
         """
         dir_status_list = [ dir_status[status_key]
@@ -1492,24 +1464,19 @@ class LocalNodeController(NodeController):
                                     to_bridge_client):
         """Summarise the statuses for this node, among all the files used by
            the other node.
-
            to_dir_server is True if the other node is a directory server.
            to_bridge_client is True if the other node is a bridge client.
-
            Combine these alternate files by choosing the best status:
              * desc_alts: "desc" and "desc_new"
              * md_alts: "md" and "md_new"
-
            Handle these alternate formats by ignoring missing directory files,
            then choosing the worst status:
              * cons_all: "ns_cons" and "md_cons"
              * desc_all: "desc"/"desc_new" and
                           "md"/"md_new"
-
            Add an "node_dir" status that describes the overall status, which
            is the worst status among descriptors, consensuses, and the bridge
            networkstatus (if relevant). Return this status.
-
            Returns None if no status is expected.
         """
         from_bridge = self.getBridge()
@@ -1608,13 +1575,10 @@ class LocalNodeController(NodeController):
                                   to_bridge_client):
         """Check all the directory paths used by another node, to see if this
            node is present.
-
            to_dir_server is True if the other node is a directory server.
            to_bridge_client is True if the other node is a bridge client.
-
            Returns a dict containing a status 3-tuple for every relevant
            directory format. See getFileDirInfoStatus() for more details.
-
            Returns None if the node doesn't have any directory files
            containing published information from this node.
         """
@@ -1643,7 +1607,6 @@ class LocalNodeController(NodeController):
     def getNodeDirInfoStatusList(self):
         """Look through the directories on each node, and work out if
            this node is in that directory.
-
            Returns a dict containing a status 3-tuple for each relevant node.
            The 3-tuple contains:
              * a status code,
@@ -1651,14 +1614,11 @@ class LocalNodeController(NodeController):
              * a status message string.
            See getNodeCacheDirInfoStatus() and getFileDirInfoStatus() for
            more details.
-
            If this node is a directory authority, bridge authority, or relay
            (including exits), checks v3 directory consensuses, descriptors,
            microdesc consensuses, and microdescriptors.
-
            If this node is a bridge, checks bridge networkstatuses, and
            descriptors on bridge authorities and bridge clients.
-
            If this node is a client (including onion services), returns None.
         """
         dir_files = self.getNodePublishedDirInfoPaths()
@@ -1696,7 +1656,6 @@ class LocalNodeController(NodeController):
     def summariseNodeDirInfoStatus(self, dir_status):
         """Summarise the statuses for this node's descriptor, among all the
            directory files used by all other nodes.
-
            Returns a dict containing a status 4-tuple for each status code.
            The 4-tuple contains:
              * a status code,
@@ -1706,11 +1665,9 @@ class LocalNodeController(NodeController):
              * a status message string.
            See getNodeCacheDirInfoStatus() and getFileDirInfoStatus() for
            more details.
-
            Also add an "node_all" status that describes the overall status,
            which is the worst status among all the other nodes' directory
            files.
-
            Returns None if no status is expected.
         """
         node_status = dict()
@@ -1777,7 +1734,6 @@ class LocalNodeController(NodeController):
     def getNodeDirInfoStatus(self):
         """Return a 4-tuple describing the status of this node's descriptor,
            in all the directory documents across the network.
-
            If this node does not have a descriptor, returns None.
         """
         dir_status = self.getNodeDirInfoStatusList()
@@ -1799,7 +1755,6 @@ class LocalNodeController(NodeController):
     def isInExpectedDirInfoDocs(self):
         """Return True if the descriptors for this node are in all expected
            directory documents.
-
            Return None if this node does not publish descriptors.
         """
         node_status = self.getNodeDirInfoStatus()
@@ -1892,9 +1847,7 @@ class TorEnviron(chutney.Templating.Environ):
 
     """Subclass of chutney.Templating.Environ to implement commonly-used
        substitutions.
-
        Environment fields provided:
-
           orport, controlport, socksport, dirport: *Port torrc option
           dir: DataDirectory torrc option
           nick: Nickname torrc option
@@ -1913,7 +1866,6 @@ class TorEnviron(chutney.Templating.Environ):
              Chutney users can disable the sandbox using:
                 export CHUTNEY_TOR_SANDBOX=0
              if it doesn't work on their version of glibc.
-
        Environment fields used:
           nodenum: chutney's internal node number for the node
           tag: a short text string that represents the type of node





More information about the tor-commits mailing list