[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[or-cvs] r20737: {projects} Apply a couple of changes according to atagar's suggestions. (projects/archives/trunk/exonerator)



Author: kloesing
Date: 2009-10-03 18:47:59 -0400 (Sat, 03 Oct 2009)
New Revision: 20737

Modified:
   projects/archives/trunk/exonerator/exonerator.py
Log:
Apply a couple of changes according to atagar's suggestions. Thanks!


Modified: projects/archives/trunk/exonerator/exonerator.py
===================================================================
--- projects/archives/trunk/exonerator/exonerator.py	2009-10-03 18:02:37 UTC (rev 20736)
+++ projects/archives/trunk/exonerator/exonerator.py	2009-10-03 22:47:59 UTC (rev 20737)
@@ -8,231 +8,134 @@
 from optparse import OptionParser
 from IPy import IP
 
-# check parameters
-usage = "usage: %prog [options] <IP address in question> " \
+USAGE = "usage: %prog [options] <IP address in question> " \
         "<timestamp, in UTC, formatted as YYYY-MM-DD hh:mm:ss> " \
         "[<target address>[:<target port>]]"
-parser = OptionParser(usage=usage)
-parser.add_option("-a", "--archive", dest="archive", default="data/",
-                  help="descriptor archive directory")
-(options, args) = parser.parse_args()
-if len(args) not in (3, 4):
-    parser.error("incorrect number of arguments")
-if not os.path.isdir(options.archive):
-    parser.error("descriptor archive directory %s does not exist or is " \
-                 "not a directory." % os.path.abspath(archiveDirectory))
-archiveDirectory = os.path.dirname(options.archive)
-try:
-    relayIP = IP(args[0])
-except ValueError:
-    parser.error("invalid IP address in question: '%s'" % args[0])
-timestampStr = "%s %s" % (args[1], args[2])
-os.environ['TZ'] = 'UTC'
-time.tzset()
-try:
-    timestamp = time.strptime(timestampStr, "%Y-%m-%d %H:%M:%S")
-except ValueError:
-    parser.error("incorrect time format: '%s'" % timestampStr)
-# if a target is given, parse address and possibly port part of it
-target = None
-targetIP = None
-targetPort = None
-if len(args) == 4:
-    target = args[3]
-    targetParts = target.split(":")
+DELIMITER = "-" * 75
+
+if __name__ == '__main__':
+    # check parameters
+    parser = OptionParser(usage=USAGE)
+    parser.add_option("-a", "--archive", dest="archive", default="data/",
+                      help="descriptor archive directory")
+    (options, args) = parser.parse_args()
+    if len(args) not in (3, 4):
+        parser.error("incorrect number of arguments")
+    if not os.path.isdir(options.archive):
+        parser.error("descriptor archive directory %s does not exist or " \
+                     "is not a directory." % \
+                     os.path.abspath(options.archive))
+    archiveDirectory = os.path.dirname(options.archive)
     try:
-        targetIP = IP(targetParts[0])
+        relayIP = IP(args[0])
     except ValueError:
-        parser.error("invalid target IP address in: '%s'" % args[3])
-    if len(targetParts) > 2:
-        parser.error("invalid target format: '%s'" % args[3])
-    if len(targetParts) > 1:
+        parser.error("invalid IP address in question: '%s'" % args[0])
+    timestampStr = "%s %s" % (args[1], args[2])
+    os.environ['TZ'] = 'UTC'
+    time.tzset()
+    try:
+        timestamp = time.strptime(timestampStr, "%Y-%m-%d %H:%M:%S")
+    except ValueError:
+        parser.error("incorrect time format: '%s'" % timestampStr)
+    # if a target is given, parse address and possibly port part of it
+    target = None
+    targetIP = None
+    targetPort = None
+    if len(args) == 4:
+        target = args[3]
+        targetParts = target.split(":")
         try:
-            targetPortTest = int(targetParts[1])
+            targetIP = IP(targetParts[0])
         except ValueError:
-            parser.error("invalid target port number in: '%s'" % args[3])
-        if targetPortTest not in range(1, 65535):
-            parser.error("invalid target port number in: '%s'" % args[3])
-        targetPort = targetParts[1]
+            parser.error("invalid target IP address in: '%s'" % args[3])
+        if len(targetParts) > 2:
+            parser.error("invalid target format: '%s'" % args[3])
+        if len(targetParts) > 1:
+            try:
+                targetPortTest = int(targetParts[1])
+            except ValueError:
+                parser.error("invalid target port number in: '%s'" % \
+                             args[3])
+            if targetPortTest not in range(1, 65535):
+                parser.error("invalid target port number in: '%s'" % \
+                             args[3])
+            targetPort = targetParts[1]
 
-DELIMITER = "-----------------------------------------------------------" \
-            "----------------"
-targetHelpStr = ""
-if target:
-    targetHelpStr = " permitting exiting to %s" % target
-print "\nTrying to find out whether %s was running a Tor relay at " \
-      "%s%s...\n\n%s\n" % (relayIP, timestampStr, targetHelpStr, DELIMITER)
+    targetHelpStr = ""
+    if target:
+        targetHelpStr = " permitting exiting to %s" % target
+    print "\nTrying to find out whether %s was running a Tor relay at " \
+          "%s%s...\n\n%s\n" % (relayIP, timestampStr, targetHelpStr,
+          DELIMITER)
 
-# check that we have the required archives
-timestampTooOld = time.gmtime(time.mktime(timestamp) - 300 * 60)
-timestampFrom = time.gmtime(time.mktime(timestamp) - 180 * 60)
-timestampTooNew = time.gmtime(time.mktime(timestamp) + 120 * 60)
-timestampTooOldStr = time.strftime("%Y-%m-%d %H:%M:%S", timestampTooOld)
-timestampFromStr = time.strftime("%Y-%m-%d %H:%M:%S", timestampFrom)
-timestampTooNewStr = time.strftime("%Y-%m-%d %H:%M:%S", timestampTooNew)
-print "\nChecking that relevant archives between %s and %s are " \
-      "available..." % (timestampTooOldStr, timestampTooNewStr)
+    # check that we have the required archives
+    timestampTooOld = time.gmtime(time.mktime(timestamp) - 300 * 60)
+    timestampFrom = time.gmtime(time.mktime(timestamp) - 180 * 60)
+    timestampTooNew = time.gmtime(time.mktime(timestamp) + 120 * 60)
+    timestampTooOldStr = time.strftime("%Y-%m-%d %H:%M:%S",
+                                       timestampTooOld)
+    timestampFromStr = time.strftime("%Y-%m-%d %H:%M:%S", timestampFrom)
+    timestampTooNewStr = time.strftime("%Y-%m-%d %H:%M:%S",
+                                       timestampTooNew)
+    print "\nChecking that relevant archives between %s and %s are " \
+          "available..." % (timestampTooOldStr, timestampTooNewStr)
 
-requiredDirs = set()
-requiredDirs.add(time.strftime("consensuses-%Y-%m", timestampTooOld))
-requiredDirs.add(time.strftime("consensuses-%Y-%m", timestampTooNew))
-if target is not None:
-    requiredDirs.add(time.strftime("server-descriptors-%Y-%m",
-                                      timestampTooOld))
-    requiredDirs.add(time.strftime("server-descriptors-%Y-%m",
-                                      timestampTooNew))
+    requiredDirs = set()
+    requiredDirs.add(time.strftime("consensuses-%Y-%m", timestampTooOld))
+    requiredDirs.add(time.strftime("consensuses-%Y-%m", timestampTooNew))
+    if target:
+        requiredDirs.add(time.strftime("server-descriptors-%Y-%m",
+                                          timestampTooOld))
+        requiredDirs.add(time.strftime("server-descriptors-%Y-%m",
+                                          timestampTooNew))
 
-consensusDirs = list()
-descriptorsDirs = list()
-directoriesLeftToParse = list()
-directoriesLeftToParse.append(archiveDirectory)
+    consensusDirs = list()
+    descriptorsDirs = list()
+    directoriesLeftToParse = list()
+    directoriesLeftToParse.append(archiveDirectory)
 
-while len(directoriesLeftToParse) > 0:
-    directoryOrFile = directoriesLeftToParse.pop()
-    basename = os.path.basename(directoryOrFile)
-    if basename.startswith("consensuses-"):
-        if basename in requiredDirs:
-            requiredDirs.remove(basename)
-            consensusDirs.append(directoryOrFile)
-    elif basename.startswith("server-descriptors-"):
-        if basename in requiredDirs:
-            requiredDirs.remove(basename)
-            descriptorsDirs.append(directoryOrFile)
-    else:
-        for filename in os.listdir(directoryOrFile):
-            entry = "%s/%s" % (directoryOrFile, filename)
-            if os.path.isdir(entry):
-                directoriesLeftToParse.append(entry)
+    while directoriesLeftToParse:
+        directoryOrFile = directoriesLeftToParse.pop()
+        basename = os.path.basename(directoryOrFile)
+        if basename.startswith("consensuses-"):
+            if basename in requiredDirs:
+                requiredDirs.remove(basename)
+                consensusDirs.append(directoryOrFile)
+        elif basename.startswith("server-descriptors-"):
+            if basename in requiredDirs:
+                requiredDirs.remove(basename)
+                descriptorsDirs.append(directoryOrFile)
+        else:
+            for filename in os.listdir(directoryOrFile):
+                entry = "%s/%s" % (directoryOrFile, filename)
+                if os.path.isdir(entry):
+                    directoriesLeftToParse.append(entry)
 
-consensusDirs.sort()
-for file in consensusDirs:
-    print "  %s" % file
-descriptorsDirs.sort()
-for file in descriptorsDirs:
-    print "  %s" % file
+    consensusDirs.sort()
+    for consensusDir in consensusDirs:
+        print "  %s" % consensusDir
+    descriptorsDirs.sort()
+    for descriptorsDir in descriptorsDirs:
+        print "  %s" % descriptorsDir
 
-if len(requiredDirs) > 0:
-    print "\nWe are missing consensuses and/or server descriptors. " \
-          "Please download these archives and extract them to your data " \
-          "directory. Be sure NOT to rename the extracted directories " \
-          "or the contained files."
-    missingFiles = list()
-    for file in sorted(requiredDirs):
-        print "  %s.tar.bz2" % file
-    sys.exit()
+    if requiredDirs:
+        print "\nWe are missing consensuses and/or server descriptors. " \
+              "Please download these archives and extract them to your " \
+              "data directory. Be sure NOT to rename the extracted " \
+              "directories or the contained files."
+        missingFiles = list()
+        for requiredDir in sorted(requiredDirs):
+            print "  %s.tar.bz2" % requiredDir
+        sys.exit()
 
-# look for consensus files
-print "\nLooking for relevant consensuses between %s and %s..." % \
-      (timestampFromStr, timestampStr)
-tooOldConsensuses = set()
-relevantConsensuses = set()
-tooNewConsensuses = set()
-directoriesLeftToParse = list()
-for file in consensusDirs:
-    directoriesLeftToParse.append(file)
-while len(directoriesLeftToParse) > 0:
-    directoryOrFile = directoriesLeftToParse.pop()
-    if os.path.isdir(directoryOrFile):
-        for filename in os.listdir(directoryOrFile):
-            entry = "%s/%s" % (directoryOrFile, filename)
-            directoriesLeftToParse.append(entry)
-    else:
-        basename = os.path.basename(directoryOrFile)
-        if (basename.endswith("consensus")):
-            consensusTime = time.strptime(basename[0:19],
-                                          "%Y-%m-%d-%H:%M:%S")
-            if consensusTime >= timestampTooOld and \
-               consensusTime < timestampFrom:
-                tooOldConsensuses.add(directoryOrFile)
-            elif consensusTime >= timestampFrom and \
-                 consensusTime <= timestamp:
-                relevantConsensuses.add(directoryOrFile)
-            elif consensusTime > timestamp and \
-                 consensusTime <= timestampTooNew:
-                tooNewConsensuses.add(directoryOrFile)
-allConsensuses = set()
-for file in tooOldConsensuses:
-    allConsensuses.add(file)
-for file in relevantConsensuses:
-    allConsensuses.add(file)
-for file in tooNewConsensuses:
-    allConsensuses.add(file)
-if len(allConsensuses) == 0:
-    print "  None found!\n\n%s\n\nResult is INDECISIVE!\n\nWe cannot " \
-          "make any statement about IP address %s being a relay at %s " \
-          "or not! We did not find any relevant consensuses preceding " \
-          "the given time. This either means that you did not download " \
-          "and extract the consensus archives preceding the hours " \
-          "before the given time, or (in rare cases) that the directory " \
-          "archives are missing the hours before the timestamp. Please " \
-          "check that your directory archives contain consensus files " \
-          "of the interval 5:00 hours before and 2:00 hours after the " \
-          "time you are looking for.\n" % \
-          (DELIMITER, relayIP, timestampStr)
-    sys.exit()
-for file in sorted(relevantConsensuses):
-    print "  %s" % file
-
-# parse consensuses to find descriptors belonging to the IP address
-print "\nLooking for descriptor identifiers referenced in \"r \" lines " \
-      "in these consensuses containing IP address %s..." % relayIP
-positiveConsensusesNoTarget = set()
-addressesInSameNetwork = set()
-relevantDescriptors = dict()
-for consensus in allConsensuses:
-    if consensus in relevantConsensuses:
-        print "  %s" % consensus
-    file = open(consensus, "r")
-    line = file.readline()
-    while line:
-        if line.startswith("r "):
-            address = IP(line.split(" ")[6])
-            if address == relayIP:
-                hexDesc = binascii.b2a_hex(binascii.a2b_base64(
-                                           line.split(" ")[3] + "=="))
-                if hexDesc not in relevantDescriptors.keys():
-                    relevantDescriptors[hexDesc] = set()
-                relevantDescriptors[hexDesc].add(consensus)
-                positiveConsensusesNoTarget.add(consensus)
-                if consensus in relevantConsensuses:
-                    print "    \"%s\" references descriptor %s" % \
-                          (line.rstrip(), hexDesc)
-            elif relayIP.overlaps(IP("%s/24" % address, make_net=True)):
-                addressesInSameNetwork.add(address)
-        line = file.readline()
-    file.close()
-if len(relevantDescriptors) == 0:
-    print "  None found!\n\n%s\n\nResult is NEGATIVE with moderate " \
-          "certainty!\n\nWe did not find IP address %s in any of the " \
-          "consensuses that were published between %s and %s.\n\nA " \
-          "possible reason for false negatives is that the relay is " \
-          "using a different IP address when generating a descriptor " \
-          "than for exiting to the Internet. We hope to provide better " \
-          "checks for this case in the future." % \
-          (DELIMITER, relayIP, timestampTooOldStr, timestampTooNewStr)
-    if len(addressesInSameNetwork) > 0:
-        print "\nThe following other IP addresses of Tor relays were " \
-              "found in the mentioned consensus files that are in the " \
-              "same /24 network and that could be related to IP address " \
-              "%s:" % relayIP
-        for addr in addressesInSameNetwork:
-            print "  %s" % addr
-    print ""
-    sys.exit()
-
-# parse router descriptors to check exit policies
-positiveConsensuses = set()
-missingDescriptors = set()
-if target is not None:
-    print "\nChecking if referenced descriptors permit exiting to " \
-          "%s..." % target
-    descriptors = relevantDescriptors.keys()
-    for desc in descriptors:
-        missingDescriptors.add(desc)
-    directoriesLeftToParse = list()
-    for descriptorsDir in descriptorsDirs:
-        directoriesLeftToParse.append(descriptorsDir)
-    while len (directoriesLeftToParse) > 0:
+    # look for consensus files
+    print "\nLooking for relevant consensuses between %s and %s..." % \
+          (timestampFromStr, timestampStr)
+    tooOldConsensuses = set()
+    relevantConsensuses = set()
+    tooNewConsensuses = set()
+    directoriesLeftToParse = list(consensusDirs)
+    while directoriesLeftToParse:
         directoryOrFile = directoriesLeftToParse.pop()
         if os.path.isdir(directoryOrFile):
             for filename in os.listdir(directoryOrFile):
@@ -240,127 +143,233 @@
                 directoriesLeftToParse.append(entry)
         else:
             basename = os.path.basename(directoryOrFile)
-            for descriptor in descriptors:
-                if basename == descriptor:
-                    missingDescriptors.remove(descriptor)
-                    file = open(directoryOrFile, "r")
-                    line = file.readline()
-                    while line:
-                        if line.startswith("reject ") or \
-                           line.startswith("accept "):
-                            ruleAccept = line.split()[0] == "accept"
-                            ruleAddress = line.split()[1].split(":")[0]
-                            if ruleAddress != "*" and not \
-                               IP(ruleAddress).overlaps(targetIP):
-                                # IP address does not match
-                                line = file.readline()
-                                continue
-                            rulePort = line.split()[1].split(":")[1]
-                            if targetPort is None and not ruleAccept and \
-                               rulePort != "*":
-                                # with no port given, we only consider
-                                # reject :* rules as matching
-                                line = file.readline()
-                                continue
-                            if targetPort and rulePort != "*" and \
-                               targetPort != rulePort:
-                                # ports do not match
-                                line = file.readline()
-                                continue
-                            relevantMatch = False
-                            for f in relevantDescriptors.get(descriptor):
-                                if f in relevantConsensuses:
-                                    relevantMatch = True
-                            if relevantMatch:
+            if (basename.endswith("consensus")):
+                consensusTime = time.strptime(basename[0:19],
+                                              "%Y-%m-%d-%H:%M:%S")
+                if consensusTime >= timestampTooOld and \
+                   consensusTime < timestampFrom:
+                    tooOldConsensuses.add(directoryOrFile)
+                elif consensusTime >= timestampFrom and \
+                     consensusTime <= timestamp:
+                    relevantConsensuses.add(directoryOrFile)
+                elif consensusTime > timestamp and \
+                     consensusTime <= timestampTooNew:
+                    tooNewConsensuses.add(directoryOrFile)
+    allConsensuses = set()
+    for consensus in tooOldConsensuses:
+        allConsensuses.add(consensus)
+    for consensus in relevantConsensuses:
+        allConsensuses.add(consensus)
+    for consensus in tooNewConsensuses:
+        allConsensuses.add(consensus)
+    if not allConsensuses:
+        print "  None found!\n\n%s\n\nResult is INDECISIVE!\n\nWe " \
+              "cannot make any statement about IP address %s being a " \
+              "relay at %s or not! We did not find any relevant " \
+              "consensuses preceding the given time. This either means " \
+              "that you did not download and extract the consensus " \
+              "archives preceding the hours before the given time, or " \
+              "(in rare cases) that the directory archives are missing " \
+              "the hours before the timestamp. Please check that your " \
+              "directory archives contain consensus files of the " \
+              "interval 5:00 hours before and 2:00 hours after the time " \
+              "you are looking for.\n" % (DELIMITER, relayIP, timestampStr)
+        sys.exit()
+    for consensus in sorted(relevantConsensuses):
+        print "  %s" % consensus
+
+    # parse consensuses to find descriptors belonging to the IP address
+    print "\nLooking for descriptor identifiers referenced in \"r \" " \
+          "lines in these consensuses containing IP address %s..." % \
+          relayIP
+    positiveConsensusesNoTarget = set()
+    addressesInSameNetwork = set()
+    relevantDescriptors = dict()
+    for consensus in allConsensuses:
+        if consensus in relevantConsensuses:
+            print "  %s" % consensus
+        consensusFile = open(consensus, "r")
+        line = consensusFile.readline()
+        while line:
+            if line.startswith("r "):
+                address = IP(line.split(" ")[6])
+                if address == relayIP:
+                    hexDesc = binascii.b2a_hex(binascii.a2b_base64(
+                                               line.split(" ")[3] + "=="))
+                    if hexDesc not in relevantDescriptors.keys():
+                        relevantDescriptors[hexDesc] = set()
+                    relevantDescriptors[hexDesc].add(consensus)
+                    positiveConsensusesNoTarget.add(consensus)
+                    if consensus in relevantConsensuses:
+                        print "    \"%s\" references descriptor %s" % \
+                              (line.rstrip(), hexDesc)
+                elif relayIP.overlaps(IP("%s/24" % address,
+                                         make_net=True)):
+                    addressesInSameNetwork.add(address)
+            line = consensusFile.readline()
+        consensusFile.close()
+    if not relevantDescriptors:
+        print "  None found!\n\n%s\n\nResult is NEGATIVE with moderate " \
+              "certainty!\n\nWe did not find IP address %s in any of " \
+              "the consensuses that were published between %s and " \
+              "%s.\n\nA possible reason for false negatives is that the " \
+              "relay is using a different IP address when generating a " \
+              "descriptor than for exiting to the Internet. We hope to " \
+              "provide better checks for this case in the future." % \
+              (DELIMITER, relayIP, timestampTooOldStr, timestampTooNewStr)
+        if addressesInSameNetwork:
+            print "\nThe following other IP addresses of Tor relays " \
+                  "were found in the mentioned consensus files that are " \
+                  "in the same /24 network and that could be related to " \
+                  "IP address %s:" % relayIP
+            for addr in addressesInSameNetwork:
+                print "  %s" % addr
+        print ""
+        sys.exit()
+
+    # parse router descriptors to check exit policies
+    positiveConsensuses = set()
+    missingDescriptors = set()
+    if target:
+        print "\nChecking if referenced descriptors permit exiting to " \
+              "%s..." % target
+        descriptors = relevantDescriptors.keys()
+        for desc in descriptors:
+            missingDescriptors.add(desc)
+        directoriesLeftToParse = list(descriptorsDirs)
+        while directoriesLeftToParse:
+            directoryOrFile = directoriesLeftToParse.pop()
+            if os.path.isdir(directoryOrFile):
+                for filename in os.listdir(directoryOrFile):
+                    entry = "%s/%s" % (directoryOrFile, filename)
+                    directoriesLeftToParse.append(entry)
+            else:
+                basename = os.path.basename(directoryOrFile)
+                for descriptor in descriptors:
+                    if basename == descriptor:
+                        missingDescriptors.remove(descriptor)
+                        descriptorFile = open(directoryOrFile, "r")
+                        line = descriptorFile.readline()
+                        while line:
+                            if line.startswith("reject ") or \
+                               line.startswith("accept "):
+                                ruleAccept = line.split()[0] == "accept"
+                                ruleAddress = line.split()[1].split(":")[0]
+                                if ruleAddress != "*" and not \
+                                   IP(ruleAddress).overlaps(targetIP):
+                                    # IP address does not match
+                                    line = descriptorFile.readline()
+                                    continue
+                                rulePort = line.split()[1].split(":")[1]
+                                if not targetPort and not ruleAccept and \
+                                   rulePort != "*":
+                                    # with no port given, we only consider
+                                    # reject :* rules as matching
+                                    line = descriptorFile.readline()
+                                    continue
+                                if targetPort and rulePort != "*" and \
+                                   targetPort != rulePort:
+                                    # ports do not match
+                                    line = descriptorFile.readline()
+                                    continue
+                                relevantMatch = False
+                                for f in relevantDescriptors.get(
+                                                             descriptor):
+                                    if f in relevantConsensuses:
+                                        relevantMatch = True
+                                if relevantMatch:
+                                    if ruleAccept:
+                                        print "  %s permits exiting to " \
+                                              "%s according to rule " \
+                                              "\"%s\"" % (directoryOrFile,
+                                              target, line.rstrip())
+                                    else:
+                                        print "  %s does not permit " \
+                                              "exiting to %s according " \
+                                              "to rule \"%s\"" % \
+                                              (directoryOrFile,
+                                              target, line.rstrip())
                                 if ruleAccept:
-                                    print "  %s permits exiting to %s " \
-                                          "according to rule \"%s\"" % \
-                                          (directoryOrFile, target,
-                                          line.rstrip())
-                                else:
-                                    print "  %s does not permit exiting " \
-                                          "to %s according to rule " \
-                                          "\"%s\"" % (directoryOrFile,
-                                          target, line.rstrip())
-                            if ruleAccept:
-                                for consensus in \
-                                    relevantDescriptors.get(descriptor):
-                                    positiveConsensuses.add(consensus)
-                            break;
-                        line = file.readline()
-                    file.close()
+                                    for consensus in \
+                                        relevantDescriptors.get(
+                                                            descriptor):
+                                        positiveConsensuses.add(consensus)
+                                break
+                            line = descriptorFile.readline()
+                        descriptorFile.close()
 
-# print out result
-matches = None
-if target:
-    matches = positiveConsensuses
-else:
-    matches = positiveConsensusesNoTarget
-lastConsensus = sorted(relevantConsensuses)[len(relevantConsensuses) - 1]
-if lastConsensus in matches:
-    print "\n%s\n\nResult is POSITIVE with high certainty!\n\nWe found " \
-          "one or more relays on IP address %s%s in the most recent " \
-          "consensus preceding %s that clients were likely to know.\n" % \
-          (DELIMITER, relayIP, targetHelpStr, timestampStr)
-    sys.exit()
-resultIndecisive = target and len(missingDescriptors) > 0
-if resultIndecisive:
-    print "\n%s\n\nResult is INDECISIVE!\n\nAt least one referenced " \
-          "descriptor could not be found. This is a rare case, but one " \
-          "that (apparently) happens. We cannot make any good statement " \
-          "about exit relays without these descriptors. The following " \
-          "descriptors are missing:" % DELIMITER
-    for desc in missingDescriptors:
-        print "  %s" % desc
-inOtherRelevantConsensus = False
-inTooOldConsensuses = False
-inTooNewConsensuses = False
-for f in matches:
-    if f in relevantConsensuses:
-        inOtherRelevantConsensus = True
-    elif f in tooOldConsensuses:
-        inTooOldConsensuses = True
-    elif f in tooNewConsensuses:
-        inTooNewConsensuses = True
-if inOtherRelevantConsensus:
-    if not resultIndecisive:
-        print "\n%s\n\nResult is POSITIVE with moderate certainty!" % \
+    # print out result
+    matches = None
+    if target:
+        matches = positiveConsensuses
+    else:
+        matches = positiveConsensusesNoTarget
+    lastConsensus = sorted(relevantConsensuses)[len(relevantConsensuses)-1]
+    if lastConsensus in matches:
+        print "\n%s\n\nResult is POSITIVE with high certainty!\n\nWe " \
+              "found one or more relays on IP address %s%s in the most " \
+              "recent consensus preceding %s that clients were likely " \
+              "to know.\n" % (DELIMITER, relayIP, targetHelpStr,
+              timestampStr)
+        sys.exit()
+    resultIndecisive = target and len(missingDescriptors) > 0
+    if resultIndecisive:
+        print "\n%s\n\nResult is INDECISIVE!\n\nAt least one " \
+              "referenced descriptor could not be found. This is a rare " \
+              "case, but one that (apparently) happens. We cannot make " \
+              "any good statement about exit relays without these " \
+              "descriptors. The following descriptors are missing:" % \
               DELIMITER
-    print "\nWe found one or more relays on IP address %s%s, but not in " \
-          "the consensus immediately preceding %s. A possible reason " \
-          "for the relay being missing in the last consensus preceding " \
-          "the given time might be that some of the directory " \
-          "authorities had difficulties connecting to the relay. " \
-          "However, clients might still have used the relay." % (relayIP,
-          targetHelpStr, timestampStr)
-else:
-    if not resultIndecisive:
-        print "\n%s\n\nResult is NEGATIVE with high certainty!" % \
-              DELIMITER
-    print "\nWe did not find any relay on IP address %s%s in the " \
-          "consensuses 3:00 hours preceding %s." % (relayIP, targetHelpStr,
-          timestampStr)
-    if inTooOldConsensuses or inTooNewConsensuses:
-        if inTooOldConsensuses and not inTooNewConsensuses:
-            print "\nNote that we found a matching relay in consensuses " \
-                  "that were published between 5:00 and 3:00 hours " \
-                  "before %s." % timestampStr
-        elif not inTooOldConsensuses and inTooNewConsensuses:
-            print "\nNote that we found a matching relay in consensuses " \
-                  "that were published up to 2:00 hours after %s." % \
-                  timestampStr
-        else:
-            print "\nNote that we found a matching relay in consensuses " \
-                  "that were published between 5:00 and 3:00 hours " \
-                  "before and in consensuses that were published up to " \
-                  "2:00 hours after %s." % timestampStr
-        print "Make sure that the timestamp you provided is in the " \
-              "correct timezone: UTC (or GMT)."
-if target:
-    if len(positiveConsensuses) == 0 and \
-       len(positiveConsensusesNoTarget) > 0:
-        print "\nNote that although the found relay(s) did not permit " \
-              "exiting to %s there have been one or more relays running " \
-              "at the given time." % target
-print ""
-
+        for desc in missingDescriptors:
+            print "  %s" % desc
+    inOtherRelevantConsensus = False
+    inTooOldConsensuses = False
+    inTooNewConsensuses = False
+    for f in matches:
+        if f in relevantConsensuses:
+            inOtherRelevantConsensus = True
+        elif f in tooOldConsensuses:
+            inTooOldConsensuses = True
+        elif f in tooNewConsensuses:
+            inTooNewConsensuses = True
+    if inOtherRelevantConsensus:
+        if not resultIndecisive:
+            print "\n%s\n\nResult is POSITIVE with moderate certainty!" % \
+                  DELIMITER
+        print "\nWe found one or more relays on IP address %s%s, but " \
+              "not in the consensus immediately preceding %s. A " \
+              "possible reason for the relay being missing in the last " \
+              "consensus preceding the given time might be that some of " \
+              "the directory authorities had difficulties connecting to " \
+              "the relay. However, clients might still have used the " \
+              "relay." % (relayIP, targetHelpStr, timestampStr)
+    else:
+        if not resultIndecisive:
+            print "\n%s\n\nResult is NEGATIVE with high certainty!" % \
+                  DELIMITER
+        print "\nWe did not find any relay on IP address %s%s in the " \
+              "consensuses 3:00 hours preceding %s." % (relayIP,
+              targetHelpStr, timestampStr)
+        if inTooOldConsensuses or inTooNewConsensuses:
+            if inTooOldConsensuses and not inTooNewConsensuses:
+                print "\nNote that we found a matching relay in " \
+                      "consensuses that were published between 5:00 and " \
+                      "3:00 hours before %s." % timestampStr
+            elif not inTooOldConsensuses and inTooNewConsensuses:
+                print "\nNote that we found a matching relay in " \
+                      "consensuses that were published up to 2:00 hours " \
+                      "after %s." % timestampStr
+            else:
+                print "\nNote that we found a matching relay in " \
+                      "consensuses that were published between 5:00 and " \
+                      "3:00 hours before and in consensuses that were " \
+                      "published up to 2:00 hours after %s." % timestampStr
+            print "Make sure that the timestamp you provided is in the " \
+                  "correct timezone: UTC (or GMT)."
+    if target:
+        if not positiveConsensuses and positiveConsensusesNoTarget:
+            print "\nNote that although the found relay(s) did not " \
+                  "permit exiting to %s there have been one or more " \
+                  "relays running at the given time." % target
+    print ""
+