Пример #1
0
 def new_desc_event(self, event):
   # updates self._titleStats with updated values
   conn = torTools.getConn()
   if not conn.isAlive(): return # keep old values
   
   myFingerprint = conn.getInfo("fingerprint", None)
   if not self._titleStats or not myFingerprint or (event and myFingerprint in event.idlist):
     stats = []
     bwRate = conn.getMyBandwidthRate()
     bwBurst = conn.getMyBandwidthBurst()
     bwObserved = conn.getMyBandwidthObserved()
     bwMeasured = conn.getMyBandwidthMeasured()
     labelInBytes = CONFIG["features.graph.bw.transferInBytes"]
     
     if bwRate and bwBurst:
       bwRateLabel = str_tools.get_size_label(bwRate, 1, False, labelInBytes)
       bwBurstLabel = str_tools.get_size_label(bwBurst, 1, False, labelInBytes)
       
       # if both are using rounded values then strip off the ".0" decimal
       if ".0" in bwRateLabel and ".0" in bwBurstLabel:
         bwRateLabel = bwRateLabel.replace(".0", "")
         bwBurstLabel = bwBurstLabel.replace(".0", "")
       
       stats.append("limit: %s/s" % bwRateLabel)
       stats.append("burst: %s/s" % bwBurstLabel)
     
     # Provide the observed bandwidth either if the measured bandwidth isn't
     # available or if the measured bandwidth is the observed (this happens
     # if there isn't yet enough bandwidth measurements).
     if bwObserved and (not bwMeasured or bwMeasured == bwObserved):
       stats.append("observed: %s/s" % str_tools.get_size_label(bwObserved, 1, False, labelInBytes))
     elif bwMeasured:
       stats.append("measured: %s/s" % str_tools.get_size_label(bwMeasured, 1, False, labelInBytes))
     
     self._titleStats = stats
Пример #2
0
 def getHeaderLabel(self, width, isPrimary):
   avg = (self.primaryTotal if isPrimary else self.secondaryTotal) / max(1, self.tick)
   lastAmount = self.lastPrimary if isPrimary else self.lastSecondary
   
   if isPrimary:
     return "CPU (%0.1f%%, avg: %0.1f%%):" % (lastAmount, avg)
   else:
     # memory sizes are converted from MB to B before generating labels
     usageLabel = str_tools.get_size_label(lastAmount * 1048576, 1)
     avgLabel = str_tools.get_size_label(avg * 1048576, 1)
     return "Memory (%s, avg: %s):" % (usageLabel, avgLabel)
Пример #3
0
    def getHeaderLabel(self, width, isPrimary):
        avg = (self.primaryTotal if isPrimary else self.secondaryTotal) / max(
            1, self.tick)
        lastAmount = self.lastPrimary if isPrimary else self.lastSecondary

        if isPrimary:
            return "CPU (%0.1f%%, avg: %0.1f%%):" % (lastAmount, avg)
        else:
            # memory sizes are converted from MB to B before generating labels
            usageLabel = str_tools.get_size_label(lastAmount * 1048576, 1)
            avgLabel = str_tools.get_size_label(avg * 1048576, 1)
            return "Memory (%s, avg: %s):" % (usageLabel, avgLabel)
Пример #4
0
    def _updateAccountingInfo(self):
        """
    Updates mapping used for accounting info. This includes the following keys:
    status, resetTime, read, written, readLimit, writtenLimit
    
    Any failed lookups result in a mapping to an empty string.
    """

        conn = torTools.getConn()
        queried = dict([(arg, "") for arg in ACCOUNTING_ARGS])
        queried["status"] = conn.getInfo("accounting/hibernating", None)

        # provides a nicely formatted reset time
        endInterval = conn.getInfo("accounting/interval-end", None)
        if endInterval:
            # converts from gmt to local with respect to DST
            if time.localtime()[8]: tz_offset = time.altzone
            else: tz_offset = time.timezone

            sec = time.mktime(time.strptime(
                endInterval, "%Y-%m-%d %H:%M:%S")) - time.time() - tz_offset
            if CONFIG["features.graph.bw.accounting.isTimeLong"]:
                queried["resetTime"] = ", ".join(
                    str_tools.get_time_labels(sec, True))
            else:
                days = sec / 86400
                sec %= 86400
                hours = sec / 3600
                sec %= 3600
                minutes = sec / 60
                sec %= 60
                queried["resetTime"] = "%i:%02i:%02i:%02i" % (days, hours,
                                                              minutes, sec)

        # number of bytes used and in total for the accounting period
        used = conn.getInfo("accounting/bytes", None)
        left = conn.getInfo("accounting/bytes-left", None)

        if used and left:
            usedComp, leftComp = used.split(" "), left.split(" ")
            read, written = int(usedComp[0]), int(usedComp[1])
            readLeft, writtenLeft = int(leftComp[0]), int(leftComp[1])

            queried["read"] = str_tools.get_size_label(read)
            queried["written"] = str_tools.get_size_label(written)
            queried["readLimit"] = str_tools.get_size_label(read + readLeft)
            queried["writtenLimit"] = str_tools.get_size_label(written +
                                                               writtenLeft)

        self.accountingInfo = queried
        self.accountingLastUpdated = time.time()
Пример #5
0
    def getHeaderLabel(self, width, isPrimary):
        graphType = "Download" if isPrimary else "Upload"
        stats = [""]

        # if wide then avg and total are part of the header, otherwise they're on
        # the x-axis
        if width * 2 > COLLAPSE_WIDTH:
            stats = [""] * 3
            stats[1] = "- %s" % self._getAvgLabel(isPrimary)
            stats[2] = ", %s" % self._getTotalLabel(isPrimary)

        stats[0] = "%-14s" % ("%s/sec" % str_tools.get_size_label(
            (self.lastPrimary if isPrimary else self.lastSecondary) * 1024, 1,
            False, CONFIG["features.graph.bw.transferInBytes"]))

        # drops label's components if there's not enough space
        labeling = graphType + " (" + "".join(stats).strip() + "):"
        while len(labeling) >= width:
            if len(stats) > 1:
                del stats[-1]
                labeling = graphType + " (" + "".join(stats).strip() + "):"
            else:
                labeling = graphType + ":"
                break

        return labeling
Пример #6
0
        def tutorial_example():
            from stem.control import Controller
            from stem.util import str_tools

            # provides a mapping of observed bandwidth to the relay nicknames
            def get_bw_to_relay():
                bw_to_relay = {}

                with Controller.from_port(control_port=9051) as controller:
                    controller.authenticate()

                    for desc in controller.get_server_descriptors():
                        if desc.exit_policy.is_exiting_allowed():
                            bw_to_relay.setdefault(desc.observed_bandwidth,
                                                   []).append(desc.nickname)

                return bw_to_relay

            # prints the top fifteen relays

            bw_to_relay = get_bw_to_relay()
            count = 1

            for bw_value in sorted(bw_to_relay.keys(), reverse=True):
                for nickname in bw_to_relay[bw_value]:
                    print "%i. %s (%s/s)" % (
                        count, nickname, str_tools.get_size_label(bw_value, 2))
                    count += 1

                    if count > 15:
                        return
Пример #7
0
    def tutorial_example():
      from stem.descriptor.remote import DescriptorDownloader
      from stem.util import str_tools

      # provides a mapping of observed bandwidth to the relay nicknames
      def get_bw_to_relay():
        bw_to_relay = {}

        downloader = DescriptorDownloader()

        try:
          for desc in downloader.get_server_descriptors().run():
            if desc.exit_policy.is_exiting_allowed():
              bw_to_relay.setdefault(desc.observed_bandwidth, []).append(desc.nickname)
        except Exception as exc:
          print "Unable to retrieve the server descriptors: %s" % exc

        return bw_to_relay

      # prints the top fifteen relays

      bw_to_relay = get_bw_to_relay()
      count = 1

      for bw_value in sorted(bw_to_relay.keys(), reverse = True):
        for nickname in bw_to_relay[bw_value]:
          print "%i. %s (%s/s)" % (count, nickname, str_tools.get_size_label(bw_value, 2))
          count += 1

          if count > 15:
            return
Пример #8
0
    def tutorial_example():
      from stem.control import Controller
      from stem.util import str_tools

      # provides a mapping of observed bandwidth to the relay nicknames
      def get_bw_to_relay():
        bw_to_relay = {}

        with Controller.from_port(control_port = 9051) as controller:
          controller.authenticate()

          for desc in controller.get_server_descriptors():
            if desc.exit_policy.is_exiting_allowed():
              bw_to_relay.setdefault(desc.observed_bandwidth, []).append(desc.nickname)

        return bw_to_relay

      # prints the top fifteen relays

      bw_to_relay = get_bw_to_relay()
      count = 1

      for bw_value in sorted(bw_to_relay.keys(), reverse = True):
        for nickname in bw_to_relay[bw_value]:
          print "%i. %s (%s/s)" % (count, nickname, str_tools.get_size_label(bw_value, 2))
          count += 1

          if count > 15:
            return
Пример #9
0
 def _updateAccountingInfo(self):
   """
   Updates mapping used for accounting info. This includes the following keys:
   status, resetTime, read, written, readLimit, writtenLimit
   
   Any failed lookups result in a mapping to an empty string.
   """
   
   conn = torTools.getConn()
   queried = dict([(arg, "") for arg in ACCOUNTING_ARGS])
   queried["status"] = conn.getInfo("accounting/hibernating", None)
   
   # provides a nicely formatted reset time
   endInterval = conn.getInfo("accounting/interval-end", None)
   if endInterval:
     # converts from gmt to local with respect to DST
     if time.localtime()[8]: tz_offset = time.altzone
     else: tz_offset = time.timezone
     
     sec = time.mktime(time.strptime(endInterval, "%Y-%m-%d %H:%M:%S")) - time.time() - tz_offset
     if CONFIG["features.graph.bw.accounting.isTimeLong"]:
       queried["resetTime"] = ", ".join(str_tools.get_time_labels(sec, True))
     else:
       days = sec / 86400
       sec %= 86400
       hours = sec / 3600
       sec %= 3600
       minutes = sec / 60
       sec %= 60
       queried["resetTime"] = "%i:%02i:%02i:%02i" % (days, hours, minutes, sec)
   
   # number of bytes used and in total for the accounting period
   used = conn.getInfo("accounting/bytes", None)
   left = conn.getInfo("accounting/bytes-left", None)
   
   if used and left:
     usedComp, leftComp = used.split(" "), left.split(" ")
     read, written = int(usedComp[0]), int(usedComp[1])
     readLeft, writtenLeft = int(leftComp[0]), int(leftComp[1])
     
     queried["read"] = str_tools.get_size_label(read)
     queried["written"] = str_tools.get_size_label(written)
     queried["readLimit"] = str_tools.get_size_label(read + readLeft)
     queried["writtenLimit"] = str_tools.get_size_label(written + writtenLeft)
   
   self.accountingInfo = queried
   self.accountingLastUpdated = time.time()
Пример #10
0
    def new_desc_event(self, event):
        # updates self._titleStats with updated values
        conn = torTools.getConn()
        if not conn.isAlive(): return  # keep old values

        myFingerprint = conn.getInfo("fingerprint", None)
        if not self._titleStats or not myFingerprint or (
                event and myFingerprint in event.idlist):
            stats = []
            bwRate = conn.getMyBandwidthRate()
            bwBurst = conn.getMyBandwidthBurst()
            bwObserved = conn.getMyBandwidthObserved()
            bwMeasured = conn.getMyBandwidthMeasured()
            labelInBytes = CONFIG["features.graph.bw.transferInBytes"]

            if bwRate and bwBurst:
                bwRateLabel = str_tools.get_size_label(bwRate, 1, False,
                                                       labelInBytes)
                bwBurstLabel = str_tools.get_size_label(
                    bwBurst, 1, False, labelInBytes)

                # if both are using rounded values then strip off the ".0" decimal
                if ".0" in bwRateLabel and ".0" in bwBurstLabel:
                    bwRateLabel = bwRateLabel.replace(".0", "")
                    bwBurstLabel = bwBurstLabel.replace(".0", "")

                stats.append("limit: %s/s" % bwRateLabel)
                stats.append("burst: %s/s" % bwBurstLabel)

            # Provide the observed bandwidth either if the measured bandwidth isn't
            # available or if the measured bandwidth is the observed (this happens
            # if there isn't yet enough bandwidth measurements).
            if bwObserved and (not bwMeasured or bwMeasured == bwObserved):
                stats.append("observed: %s/s" % str_tools.get_size_label(
                    bwObserved, 1, False, labelInBytes))
            elif bwMeasured:
                stats.append("measured: %s/s" % str_tools.get_size_label(
                    bwMeasured, 1, False, labelInBytes))

            self._titleStats = stats
Пример #11
0
  def test_get_size_label(self):
    """
    Checks the get_size_label() function.
    """

    # test the pydoc examples
    self.assertEquals('1 MB', str_tools.get_size_label(2000000))
    self.assertEquals('1.02 KB', str_tools.get_size_label(1050, 2))
    self.assertEquals('1.025 Kilobytes', str_tools.get_size_label(1050, 3, True))

    self.assertEquals('0 B', str_tools.get_size_label(0))
    self.assertEquals('0 Bytes', str_tools.get_size_label(0, is_long = True))
    self.assertEquals('0.00 B', str_tools.get_size_label(0, 2))
    self.assertEquals('-10 B', str_tools.get_size_label(-10))
    self.assertEquals('80 b', str_tools.get_size_label(10, is_bytes = False))
    self.assertEquals('-1 MB', str_tools.get_size_label(-2000000))

    # checking that we round down
    self.assertEquals('23.43 Kb', str_tools.get_size_label(3000, 2, is_bytes = False))

    self.assertRaises(TypeError, str_tools.get_size_label, None)
    self.assertRaises(TypeError, str_tools.get_size_label, 'hello world')
Пример #12
0
  def test_get_size_label(self):
    """
    Checks the get_size_label() function.
    """

    # test the pydoc examples
    self.assertEquals('1 MB', str_tools.get_size_label(2000000))
    self.assertEquals('1.02 KB', str_tools.get_size_label(1050, 2))
    self.assertEquals('1.025 Kilobytes', str_tools.get_size_label(1050, 3, True))

    self.assertEquals('0 B', str_tools.get_size_label(0))
    self.assertEquals('0 Bytes', str_tools.get_size_label(0, is_long = True))
    self.assertEquals('0.00 B', str_tools.get_size_label(0, 2))
    self.assertEquals('-10 B', str_tools.get_size_label(-10))
    self.assertEquals('80 b', str_tools.get_size_label(10, is_bytes = False))
    self.assertEquals('-1 MB', str_tools.get_size_label(-2000000))

    # checking that we round down
    self.assertEquals('23.43 Kb', str_tools.get_size_label(3000, 2, is_bytes = False))

    self.assertRaises(TypeError, str_tools.get_size_label, None)
    self.assertRaises(TypeError, str_tools.get_size_label, 'hello world')
Пример #13
0
  def test_mirror_mirror_on_the_wall(self):
    from stem.descriptor.server_descriptor import RelayDescriptor
    from stem.descriptor.reader import DescriptorReader
    from stem.util import str_tools

    exit_descriptor = mocking.get_relay_server_descriptor({
     'router': 'speedyexit 149.255.97.109 9001 0 0'
    }, content = True).replace('reject *:*', 'accept *:*')
    exit_descriptor = mocking.sign_descriptor_content(exit_descriptor)
    exit_descriptor = RelayDescriptor(exit_descriptor)

    reader_wrapper = mocking.get_object(DescriptorReader, {
      '__enter__': lambda x: x,
      '__exit__': mocking.no_op(),
      '__iter__': mocking.return_value(iter((
        exit_descriptor,
        mocking.get_relay_server_descriptor(),  # non-exit
        exit_descriptor,
        exit_descriptor,
      )))
    })

    # provides a mapping of observed bandwidth to the relay nicknames
    def get_bw_to_relay():
      bw_to_relay = {}

      with reader_wrapper as reader:
        for desc in reader:
          if desc.exit_policy.is_exiting_allowed():
            bw_to_relay.setdefault(desc.observed_bandwidth, []).append(desc.nickname)

      return bw_to_relay

    # prints the top fifteen relays

    bw_to_relay = get_bw_to_relay()
    count = 1

    for bw_value in sorted(bw_to_relay.keys(), reverse = True):
      for nickname in bw_to_relay[bw_value]:
        expected_line = "%i. speedyexit (102.13 KB/s)" % count
        printed_line = "%i. %s (%s/s)" % (count, nickname, str_tools.get_size_label(bw_value, 2))
        self.assertEqual(expected_line, printed_line)

        count += 1

        if count > 15:
          return

    self.assertEqual(4, count)
Пример #14
0
 def _getValue(self):
   """
   Provides the current value of the configuration entry, taking advantage of
   the torTools caching to effectively query the accurate value. This uses the
   value's type to provide a user friendly representation if able.
   """
   
   confValue = ", ".join(torTools.getConn().getOption(self.get(Field.OPTION), [], True))
   
   # provides nicer values for recognized types
   if not confValue: confValue = "<none>"
   elif self.get(Field.TYPE) == "Boolean" and confValue in ("0", "1"):
     confValue = "False" if confValue == "0" else "True"
   elif self.get(Field.TYPE) == "DataSize" and confValue.isdigit():
     confValue = str_tools.get_size_label(int(confValue))
   elif self.get(Field.TYPE) == "TimeInterval" and confValue.isdigit():
     confValue = str_tools.get_time_label(int(confValue), is_long = True)
   
   return confValue
Пример #15
0
    def _getValue(self):
        """
    Provides the current value of the configuration entry, taking advantage of
    the torTools caching to effectively query the accurate value. This uses the
    value's type to provide a user friendly representation if able.
    """

        confValue = ", ".join(torTools.getConn().getOption(self.get(Field.OPTION), [], True))

        # provides nicer values for recognized types
        if not confValue:
            confValue = "<none>"
        elif self.get(Field.TYPE) == "Boolean" and confValue in ("0", "1"):
            confValue = "False" if confValue == "0" else "True"
        elif self.get(Field.TYPE) == "DataSize" and confValue.isdigit():
            confValue = str_tools.get_size_label(int(confValue))
        elif self.get(Field.TYPE) == "TimeInterval" and confValue.isdigit():
            confValue = str_tools.get_time_label(int(confValue), is_long=True)

        return confValue
Пример #16
0
 def getHeaderLabel(self, width, isPrimary):
   graphType = "Download" if isPrimary else "Upload"
   stats = [""]
   
   # if wide then avg and total are part of the header, otherwise they're on
   # the x-axis
   if width * 2 > COLLAPSE_WIDTH:
     stats = [""] * 3
     stats[1] = "- %s" % self._getAvgLabel(isPrimary)
     stats[2] = ", %s" % self._getTotalLabel(isPrimary)
   
   stats[0] = "%-14s" % ("%s/sec" % str_tools.get_size_label((self.lastPrimary if isPrimary else self.lastSecondary) * 1024, 1, False, CONFIG["features.graph.bw.transferInBytes"]))
   
   # drops label's components if there's not enough space
   labeling = graphType + " (" + "".join(stats).strip() + "):"
   while len(labeling) >= width:
     if len(stats) > 1:
       del stats[-1]
       labeling = graphType + " (" + "".join(stats).strip() + "):"
     else:
       labeling = graphType + ":"
       break
   
   return labeling
Пример #17
0
 def _getTotalLabel(self, isPrimary):
   total = self.primaryTotal if isPrimary else self.secondaryTotal
   total += self.initialPrimaryTotal if isPrimary else self.initialSecondaryTotal
   return "total: %s" % str_tools.get_size_label(total * 1024, 1)
Пример #18
0
 def _getAvgLabel(self, isPrimary):
   total = self.primaryTotal if isPrimary else self.secondaryTotal
   total += self.prepopulatePrimaryTotal if isPrimary else self.prepopulateSecondaryTotal
   return "avg: %s/sec" % str_tools.get_size_label((total / max(1, self.tick + self.prepopulateTicks)) * 1024, 1, False, CONFIG["features.graph.bw.transferInBytes"])
Пример #19
0
def validate(contents=None):
    """
  Performs validation on the given torrc contents, providing back a listing of
  (line number, issue, msg) tuples for issues found. If the issue occures on a
  multiline torrc entry then the line number is for the last line of the entry.
  
  Arguments:
    contents - torrc contents
  """

    conn = torTools.getConn()
    customOptions = getCustomOptions()
    issuesFound, seenOptions = [], []

    # Strips comments and collapses multiline multi-line entries, for more
    # information see:
    # https://trac.torproject.org/projects/tor/ticket/1929
    strippedContents, multilineBuffer = [], ""
    for line in _stripComments(contents):
        if not line: strippedContents.append("")
        else:
            line = multilineBuffer + line
            multilineBuffer = ""

            if line.endswith("\\"):
                multilineBuffer = line[:-1]
                strippedContents.append("")
            else:
                strippedContents.append(line.strip())

    for lineNumber in range(len(strippedContents) - 1, -1, -1):
        lineText = strippedContents[lineNumber]
        if not lineText: continue

        lineComp = lineText.split(None, 1)
        if len(lineComp) == 2: option, value = lineComp
        else: option, value = lineText, ""

        # Tor is case insensetive when parsing its torrc. This poses a bit of an
        # issue for us because we want all of our checks to be case insensetive
        # too but also want messages to match the normal camel-case conventions.
        #
        # Using the customOptions to account for this. It contains the tor reported
        # options (camel case) and is either a matching set or the following defaut
        # value check will fail. Hence using that hash to correct the case.
        #
        # TODO: when refactoring for stem make this less confusing...

        for customOpt in customOptions:
            if customOpt.lower() == option.lower():
                option = customOpt
                break

        # if an aliased option then use its real name
        if option in CONFIG["torrc.alias"]:
            option = CONFIG["torrc.alias"][option]

        # most parameters are overwritten if defined multiple times
        if option in seenOptions and not option in getMultilineParameters():
            issuesFound.append((lineNumber, ValidationError.DUPLICATE, option))
            continue
        else:
            seenOptions.append(option)

        # checks if the value isn't necessary due to matching the defaults
        if not option in customOptions:
            issuesFound.append(
                (lineNumber, ValidationError.IS_DEFAULT, option))

        # replace aliases with their recognized representation
        if option in CONFIG["torrc.alias"]:
            option = CONFIG["torrc.alias"][option]

        # tor appears to replace tabs with a space, for instance:
        # "accept\t*:563" is read back as "accept *:563"
        value = value.replace("\t", " ")

        # parse value if it's a size or time, expanding the units
        value, valueType = _parseConfValue(value)

        # issues GETCONF to get the values tor's currently configured to use
        torValues = conn.getOption(option, [], True)

        # multiline entries can be comma separated values (for both tor and conf)
        valueList = [value]
        if option in getMultilineParameters():
            valueList = [val.strip() for val in value.split(",")]

            fetchedValues, torValues = torValues, []
            for fetchedValue in fetchedValues:
                for fetchedEntry in fetchedValue.split(","):
                    fetchedEntry = fetchedEntry.strip()
                    if not fetchedEntry in torValues:
                        torValues.append(fetchedEntry)

        for val in valueList:
            # checks if both the argument and tor's value are empty
            isBlankMatch = not val and not torValues

            if not isBlankMatch and not val in torValues:
                # converts corrections to reader friedly size values
                displayValues = torValues
                if valueType == ValueType.SIZE:
                    displayValues = [
                        str_tools.get_size_label(int(val)) for val in torValues
                    ]
                elif valueType == ValueType.TIME:
                    displayValues = [
                        str_tools.get_time_label(int(val)) for val in torValues
                    ]

                issuesFound.append((lineNumber, ValidationError.MISMATCH,
                                    ", ".join(displayValues)))

    # checks if any custom options are missing from the torrc
    for option in customOptions:
        # In new versions the 'DirReqStatistics' option is true by default and
        # disabled on startup if geoip lookups are unavailable. If this option is
        # missing then that's most likely the reason.
        #
        # https://trac.torproject.org/projects/tor/ticket/4237

        if option == "DirReqStatistics": continue

        if not option in seenOptions:
            issuesFound.append((None, ValidationError.MISSING, option))

    return issuesFound
Пример #20
0
 def _getAvgLabel(self, isPrimary):
     total = self.primaryTotal if isPrimary else self.secondaryTotal
     total += self.prepopulatePrimaryTotal if isPrimary else self.prepopulateSecondaryTotal
     return "avg: %s/sec" % str_tools.get_size_label(
         (total / max(1, self.tick + self.prepopulateTicks)) * 1024, 1,
         False, CONFIG["features.graph.bw.transferInBytes"])
Пример #21
0
def validate(contents = None):
  """
  Performs validation on the given torrc contents, providing back a listing of
  (line number, issue, msg) tuples for issues found. If the issue occures on a
  multiline torrc entry then the line number is for the last line of the entry.
  
  Arguments:
    contents - torrc contents
  """
  
  conn = torTools.getConn()
  customOptions = getCustomOptions()
  issuesFound, seenOptions = [], []
  
  # Strips comments and collapses multiline multi-line entries, for more
  # information see:
  # https://trac.torproject.org/projects/tor/ticket/1929
  strippedContents, multilineBuffer = [], ""
  for line in _stripComments(contents):
    if not line: strippedContents.append("")
    else:
      line = multilineBuffer + line
      multilineBuffer = ""
      
      if line.endswith("\\"):
        multilineBuffer = line[:-1]
        strippedContents.append("")
      else:
        strippedContents.append(line.strip())
  
  for lineNumber in range(len(strippedContents) - 1, -1, -1):
    lineText = strippedContents[lineNumber]
    if not lineText: continue
    
    lineComp = lineText.split(None, 1)
    if len(lineComp) == 2: option, value = lineComp
    else: option, value = lineText, ""
    
    # Tor is case insensetive when parsing its torrc. This poses a bit of an
    # issue for us because we want all of our checks to be case insensetive
    # too but also want messages to match the normal camel-case conventions.
    #
    # Using the customOptions to account for this. It contains the tor reported
    # options (camel case) and is either a matching set or the following defaut
    # value check will fail. Hence using that hash to correct the case.
    #
    # TODO: when refactoring for stem make this less confusing...
    
    for customOpt in customOptions:
      if customOpt.lower() == option.lower():
        option = customOpt
        break
    
    # if an aliased option then use its real name
    if option in CONFIG["torrc.alias"]:
      option = CONFIG["torrc.alias"][option]
    
    # most parameters are overwritten if defined multiple times
    if option in seenOptions and not option in getMultilineParameters():
      issuesFound.append((lineNumber, ValidationError.DUPLICATE, option))
      continue
    else: seenOptions.append(option)
    
    # checks if the value isn't necessary due to matching the defaults
    if not option in customOptions:
      issuesFound.append((lineNumber, ValidationError.IS_DEFAULT, option))
    
    # replace aliases with their recognized representation
    if option in CONFIG["torrc.alias"]:
      option = CONFIG["torrc.alias"][option]
    
    # tor appears to replace tabs with a space, for instance:
    # "accept\t*:563" is read back as "accept *:563"
    value = value.replace("\t", " ")
    
    # parse value if it's a size or time, expanding the units
    value, valueType = _parseConfValue(value)
    
    # issues GETCONF to get the values tor's currently configured to use
    torValues = conn.getOption(option, [], True)
    
    # multiline entries can be comma separated values (for both tor and conf)
    valueList = [value]
    if option in getMultilineParameters():
      valueList = [val.strip() for val in value.split(",")]
      
      fetchedValues, torValues = torValues, []
      for fetchedValue in fetchedValues:
        for fetchedEntry in fetchedValue.split(","):
          fetchedEntry = fetchedEntry.strip()
          if not fetchedEntry in torValues:
            torValues.append(fetchedEntry)
    
    for val in valueList:
      # checks if both the argument and tor's value are empty
      isBlankMatch = not val and not torValues
      
      if not isBlankMatch and not val in torValues:
        # converts corrections to reader friedly size values
        displayValues = torValues
        if valueType == ValueType.SIZE:
          displayValues = [str_tools.get_size_label(int(val)) for val in torValues]
        elif valueType == ValueType.TIME:
          displayValues = [str_tools.get_time_label(int(val)) for val in torValues]
        
        issuesFound.append((lineNumber, ValidationError.MISMATCH, ", ".join(displayValues)))
  
  # checks if any custom options are missing from the torrc
  for option in customOptions:
    # In new versions the 'DirReqStatistics' option is true by default and
    # disabled on startup if geoip lookups are unavailable. If this option is
    # missing then that's most likely the reason.
    #
    # https://trac.torproject.org/projects/tor/ticket/4237
    
    if option == "DirReqStatistics": continue
    
    if not option in seenOptions:
      issuesFound.append((None, ValidationError.MISSING, option))
  
  return issuesFound
Пример #22
0
# Accessing controller
with Controller.from_port(port = 9151) as controller:
  controller.authenticate()
# Accessing circuits in controller 
  for circ in sorted(controller.get_circuits()):
# Filtering only 3 relay complete circuits
    if circ.status != CircStatus.BUILT or len(circ.path) < 3: 
      continue

    print 
    print "Circuit %s (%s)" % (circ.id, circ.purpose)
    cirStr = ""
# Accessing relays in each circuit
    for i, entry in enumerate(circ.path):
      if i == 0:
   	str = "Entry node"
      elif i == len(circ.path) - 1:
   	str = "Exit node"
      else:
   	str = "Middle node" 
      fingerprint, nickname = entry
      
      bw_rate = get_size_label(int(controller.get_conf('BandwidthRate', '0')))
     		
      desc = controller.get_network_status(fingerprint, None)
      address = desc.address if desc else 'unknown'
      countrycode = controller.get_info("ip-to-country/%s" % desc.address, "unknown")
      country = gi.country_name_by_addr(address)
      cirStr = cirStr + " %s: [IP: %s, Country: %s, Bandwidth: %s/s] ->" % (str, address, country, bw_rate)	
    print cirStr[:-2]
Пример #23
0
    def draw(self, width, height):
        self.valsLock.acquire()
        isWide = width + 1 >= MIN_DUAL_COL_WIDTH

        # space available for content
        if isWide:
            leftWidth = max(width / 2, 77)
            rightWidth = width - leftWidth
        else:
            leftWidth = rightWidth = width

        # Line 1 / Line 1 Left (system and tor version information)
        sysNameLabel = "arm - %s" % self.vals["sys/hostname"]
        contentSpace = min(leftWidth, 40)

        if len(sysNameLabel) + 10 <= contentSpace:
            sysTypeLabel = "%s %s" % (self.vals["sys/os"],
                                      self.vals["sys/version"])
            sysTypeLabel = uiTools.cropStr(
                sysTypeLabel, contentSpace - len(sysNameLabel) - 3, 4)
            self.addstr(0, 0, "%s (%s)" % (sysNameLabel, sysTypeLabel))
        else:
            self.addstr(0, 0, uiTools.cropStr(sysNameLabel, contentSpace))

        contentSpace = leftWidth - 43
        if 7 + len(self.vals["tor/version"]) + len(
                self.vals["tor/versionStatus"]) <= contentSpace:
            if self.vals["tor/version"] != "Unknown":
                versionColor = VERSION_STATUS_COLORS[self.vals["tor/versionStatus"]] if \
                    self.vals["tor/versionStatus"] in VERSION_STATUS_COLORS else "white"
                labelPrefix = "Tor %s (" % self.vals["tor/version"]
                self.addstr(0, 43, labelPrefix)
                self.addstr(0, 43 + len(labelPrefix),
                            self.vals["tor/versionStatus"],
                            uiTools.getColor(versionColor))
                self.addstr(
                    0, 43 + len(labelPrefix) +
                    len(self.vals["tor/versionStatus"]), ")")
        elif 11 <= contentSpace:
            self.addstr(
                0, 43,
                uiTools.cropStr("Tor %s" % self.vals["tor/version"],
                                contentSpace, 4))

        # Line 2 / Line 2 Left (tor ip/port information)
        x, includeControlPort = 0, True
        if self.vals["tor/orPort"]:
            myAddress = "Unknown"
            if self.vals["tor/orListenAddr"]:
                myAddress = self.vals["tor/orListenAddr"]
            elif self.vals["tor/address"]:
                myAddress = self.vals["tor/address"]

            # acting as a relay (we can assume certain parameters are set
            dirPortLabel = ", Dir Port: %s" % self.vals[
                "tor/dirPort"] if self.vals["tor/dirPort"] != "0" else ""
            for label in (self.vals["tor/nickname"], " - " + myAddress,
                          ":" + self.vals["tor/orPort"], dirPortLabel):
                if x + len(label) <= leftWidth:
                    self.addstr(1, x, label)
                    x += len(label)
                else:
                    break
        else:
            # non-relay (client only)
            if self._isTorConnected:
                self.addstr(1, x, "Relaying Disabled",
                            uiTools.getColor("cyan"))
                x += 17
            else:
                statusTime = torTools.getConn().getHeartbeat()

                if statusTime:
                    statusTimeLabel = time.strftime("%H:%M %m/%d/%Y, ",
                                                    time.localtime(statusTime))
                else:
                    statusTimeLabel = ""  # never connected to tor

                self.addstr(1, x, "Tor Disconnected",
                            curses.A_BOLD | uiTools.getColor("red"))
                self.addstr(1, x + 16,
                            " (%spress r to reconnect)" % statusTimeLabel)
                x += 39 + len(statusTimeLabel)
                includeControlPort = False

        if includeControlPort:
            if self.vals["tor/controlPort"] == "0":
                # connected via a control socket
                self.addstr(
                    1, x, ", Control Socket: %s" % self.vals["tor/socketPath"])
            else:
                if self.vals["tor/isAuthPassword"]: authType = "password"
                elif self.vals["tor/isAuthCookie"]: authType = "cookie"
                else: authType = "open"

                if x + 19 + len(self.vals["tor/controlPort"]) + len(
                        authType) <= leftWidth:
                    authColor = "red" if authType == "open" else "green"
                    self.addstr(1, x, ", Control Port (")
                    self.addstr(1, x + 16, authType,
                                uiTools.getColor(authColor))
                    self.addstr(1, x + 16 + len(authType),
                                "): %s" % self.vals["tor/controlPort"])
                elif x + 16 + len(self.vals["tor/controlPort"]) <= leftWidth:
                    self.addstr(
                        1, 0,
                        ", Control Port: %s" % self.vals["tor/controlPort"])

        # Line 3 / Line 1 Right (system usage info)
        y, x = (0, leftWidth) if isWide else (2, 0)
        if self.vals["stat/rss"] != "0":
            memoryLabel = str_tools.get_size_label(int(self.vals["stat/rss"]))
        else:
            memoryLabel = "0"

        uptimeLabel = ""
        if self.vals["tor/startTime"]:
            if self.isPaused() or not self._isTorConnected:
                # freeze the uptime when paused or the tor process is stopped
                uptimeLabel = str_tools.get_short_time_label(
                    self.getPauseTime() - self.vals["tor/startTime"])
            else:
                uptimeLabel = str_tools.get_short_time_label(
                    time.time() - self.vals["tor/startTime"])

        sysFields = ((0, "cpu: %s%% tor, %s%% arm" %
                      (self.vals["stat/%torCpu"], self.vals["stat/%armCpu"])),
                     (27, "mem: %s (%s%%)" %
                      (memoryLabel, self.vals["stat/%mem"])),
                     (47, "pid: %s" %
                      (self.vals["tor/pid"] if self._isTorConnected else "")),
                     (59, "uptime: %s" % uptimeLabel))

        for (start, label) in sysFields:
            if start + len(label) <= rightWidth:
                self.addstr(y, x + start, label)
            else:
                break

        if self.vals["tor/orPort"]:
            # Line 4 / Line 2 Right (fingerprint, and possibly file descriptor usage)
            y, x = (1, leftWidth) if isWide else (3, 0)

            fingerprintLabel = uiTools.cropStr(
                "fingerprint: %s" % self.vals["tor/fingerprint"], width)
            self.addstr(y, x, fingerprintLabel)

            # if there's room and we're able to retrieve both the file descriptor
            # usage and limit then it might be presented
            if width - x - 59 >= 20 and self.vals["tor/fdUsed"] and self.vals[
                    "tor/fdLimit"]:
                # display file descriptor usage if we're either configured to do so or
                # running out

                fdPercent = 100 * self.vals["tor/fdUsed"] / self.vals[
                    "tor/fdLimit"]

                if fdPercent >= 60 or CONFIG["features.showFdUsage"]:
                    fdPercentLabel, fdPercentFormat = "%i%%" % fdPercent, curses.A_NORMAL
                    if fdPercent >= 95:
                        fdPercentFormat = curses.A_BOLD | uiTools.getColor(
                            "red")
                    elif fdPercent >= 90:
                        fdPercentFormat = uiTools.getColor("red")
                    elif fdPercent >= 60:
                        fdPercentFormat = uiTools.getColor("yellow")

                    estimateChar = "?" if self.vals[
                        "tor/isFdLimitEstimate"] else ""
                    baseLabel = "file desc: %i / %i%s (" % (
                        self.vals["tor/fdUsed"], self.vals["tor/fdLimit"],
                        estimateChar)

                    self.addstr(y, x + 59, baseLabel)
                    self.addstr(y, x + 59 + len(baseLabel), fdPercentLabel,
                                fdPercentFormat)
                    self.addstr(y,
                                x + 59 + len(baseLabel) + len(fdPercentLabel),
                                ")")

            # Line 5 / Line 3 Left (flags)
            if self._isTorConnected:
                y, x = (2 if isWide else 4, 0)
                self.addstr(y, x, "flags: ")
                x += 7

                if len(self.vals["tor/flags"]) > 0:
                    for i in range(len(self.vals["tor/flags"])):
                        flag = self.vals["tor/flags"][i]
                        flagColor = FLAG_COLORS[
                            flag] if flag in FLAG_COLORS.keys() else "white"

                        self.addstr(
                            y, x, flag,
                            curses.A_BOLD | uiTools.getColor(flagColor))
                        x += len(flag)

                        if i < len(self.vals["tor/flags"]) - 1:
                            self.addstr(y, x, ", ")
                            x += 2
                else:
                    self.addstr(y, x, "none",
                                curses.A_BOLD | uiTools.getColor("cyan"))
            else:
                y = 2 if isWide else 4
                statusTime = torTools.getConn().getHeartbeat()
                statusTimeLabel = time.strftime("%H:%M %m/%d/%Y",
                                                time.localtime(statusTime))
                self.addstr(y, 0, "Tor Disconnected",
                            curses.A_BOLD | uiTools.getColor("red"))
                self.addstr(y, 16,
                            " (%s) - press r to reconnect" % statusTimeLabel)

            # Undisplayed / Line 3 Right (exit policy)
            if isWide:
                exitPolicy = self.vals["tor/exitPolicy"]

                # adds note when default exit policy is appended
                if exitPolicy == "": exitPolicy = "<default>"
                elif not exitPolicy.endswith((" *:*", " *")):
                    exitPolicy += ", <default>"

                self.addstr(2, leftWidth, "exit policy: ")
                x = leftWidth + 13

                # color codes accepts to be green, rejects to be red, and default marker to be cyan
                isSimple = len(exitPolicy) > rightWidth - 13
                policies = exitPolicy.split(", ")
                for i in range(len(policies)):
                    policy = policies[i].strip()
                    policyLabel = policy.replace("accept", "").replace(
                        "reject", "").strip() if isSimple else policy

                    policyColor = "white"
                    if policy.startswith("accept"): policyColor = "green"
                    elif policy.startswith("reject"): policyColor = "red"
                    elif policy.startswith("<default>"): policyColor = "cyan"

                    self.addstr(2, x, policyLabel,
                                curses.A_BOLD | uiTools.getColor(policyColor))
                    x += len(policyLabel)

                    if i < len(policies) - 1:
                        self.addstr(2, x, ", ")
                        x += 2
        else:
            # (Client only) Undisplayed / Line 2 Right (new identity option)
            if isWide:
                conn = torTools.getConn()
                newnymWait = conn.getNewnymWait()

                msg = "press 'n' for a new identity"
                if newnymWait > 0:
                    pluralLabel = "s" if newnymWait > 1 else ""
                    msg = "building circuits, available again in %i second%s" % (
                        newnymWait, pluralLabel)

                self.addstr(1, leftWidth, msg)

        self.valsLock.release()
Пример #24
0
 def _getTotalLabel(self, isPrimary):
     total = self.primaryTotal if isPrimary else self.secondaryTotal
     total += self.initialPrimaryTotal if isPrimary else self.initialSecondaryTotal
     return "total: %s" % str_tools.get_size_label(total * 1024, 1)