Author: atagar Date: 2011-03-27 06:07:59 +0000 (Sun, 27 Mar 2011) New Revision: 24455
Modified: arm/trunk/src/util/torConfig.py arm/trunk/src/util/torTools.py Log: Torrc validation requires 'GETINFO config-text' which was introduced in Tor verison 0.2.2.7 (as per https://trac.torproject.org/projects/tor/ticket/2501). Skipping validation if we don't meet that requirement.
Modified: arm/trunk/src/util/torConfig.py =================================================================== --- arm/trunk/src/util/torConfig.py 2011-03-27 02:58:34 UTC (rev 24454) +++ arm/trunk/src/util/torConfig.py 2011-03-27 06:07:59 UTC (rev 24455) @@ -628,13 +628,23 @@
self.valsLock.acquire()
+ # The torrc validation relies on 'GETINFO config-text' which was + # introduced in tor 0.2.2.7-alpha so if we're using an earlier version + # (or configured to skip torrc validation) then this is a no-op. For more + # information see: + # https://trac.torproject.org/projects/tor/ticket/2501 + if not self.isLoaded(): returnVal = None - elif not CONFIG["features.torrc.validate"]: returnVal = {} else: - if self.corrections == None: - self.corrections = validate(self.contents) + skipValidation = not CONFIG["features.torrc.validate"] + skipValidation |= not torTools.getConn().isVersion("0.2.2.7-alpha")
- returnVal = list(self.corrections) + if skipValidation: returnVal = {} + else: + if self.corrections == None: + self.corrections = validate(self.contents) + + returnVal = list(self.corrections)
self.valsLock.release() return returnVal
Modified: arm/trunk/src/util/torTools.py =================================================================== --- arm/trunk/src/util/torTools.py 2011-03-27 02:58:34 UTC (rev 24454) +++ arm/trunk/src/util/torTools.py 2011-03-27 06:07:59 UTC (rev 24455) @@ -54,8 +54,8 @@ CACHE_ARGS = ("version", "config-file", "exit-policy/default", "fingerprint", "config/names", "info/names", "features/names", "events/names", "nsEntry", "descEntry", "address", "bwRate", "bwBurst", - "bwObserved", "bwMeasured", "flags", "pid", "pathPrefix", - "startTime", "authorities", "circuits") + "bwObserved", "bwMeasured", "flags", "parsedVersion", "pid", + "pathPrefix", "startTime", "authorities", "circuits")
# Tor has a couple messages (in or/router.c) for when our ip address changes: # "Our IP Address has changed from <previous> to <current>; rebuilding @@ -217,6 +217,41 @@ log.log(CONFIG["log.unknownBsdJailId"], "Failed to figure out the FreeBSD jail id. Assuming 0.") return 0
+def parseVersion(versionStr): + """ + Parses the given version string into its expected components, for instance... + '0.2.2.13-alpha (git-feb8c1b5f67f2c6f)' + + would provide: + (0, 2, 2, 13, 'alpha') + + If the input isn't recognized then this returns None. + + Arguments: + versionStr - version string to be parsed + """ + + # crops off extra arguments, for instance: + # '0.2.2.13-alpha (git-feb8c1b5f67f2c6f)' -> '0.2.2.13-alpha' + versionStr = versionStr.split()[0] + + result = None + if versionStr.count(".") in (2, 3): + # parses the optional suffix ('alpha', 'release', etc) + if versionStr.count("-") == 1: + versionStr, versionSuffix = versionStr.split("-") + else: versionSuffix = "" + + # Parses the numeric portion of the version. This can have three or four + # entries depending on if an optional patch level was provided. + try: + versionComp = [int(entry) for entry in versionStr.split(".")] + if len(versionComp) == 3: versionComp += [0] + result = tuple(versionComp + [versionSuffix]) + except ValueError: pass + + return result + def getConn(): """ Singleton constructor for a Controller. Be aware that this starts as being @@ -702,6 +737,53 @@
return self._getRelayAttr("flags", default)
+ def isVersion(self, minVersionStr): + """ + Checks if we meet the given version. Recognized versions are of the form: + <major>.<minor>.<micro>[.<patch>][-<status_tag>] + + for instance, "0.2.2.13-alpha" or "0.2.1.5". This raises a ValueError if + the input isn't recognized, and returns False if unable to fetch our + instance's version. + + According to the spec the status_tag is purely informal, so it's ignored + in comparisons. + + Arguments: + minVersionStr - version to be compared against + """ + + minVersion = parseVersion(minVersionStr) + + if minVersion == None: + raise ValueError("unrecognized version: %s" % minVersionStr) + + self.connLock.acquire() + + result = False + if self.isAlive(): + myVersion = self._getRelayAttr("parsedVersion", None) + + if not myVersion: + result = False + elif myVersion[:4] == minVersion[:4]: + result = True # versions match + else: + # compares each of the numeric portions of the version + for i in range(4): + myVal, minVal = myVersion[i], minVersion[i] + + if myVal > minVal: + result = True + break + elif myVal < minVal: + result = False + break + + self.connLock.release() + + return result + def getMyPid(self): """ Provides the pid of the attached tor process (None if no controller exists @@ -1515,6 +1597,8 @@ if line.startswith("s "): result = line[2:].split() break + elif key == "parsedVersion": + result = parseVersion(self.getInfo("version", "")) elif key == "pid": result = getPid(int(self.getOption("ControlPort", 9051)), self.getOption("PidFile")) elif key == "pathPrefix":