Ejemplo n.º 1
0
    def __init__(self):
        self._my_router_status_entry = None
        self._my_router_status_entry_time = 0

        # Stem's get_network_statuses() is slow, and overkill for what we need
        # here. Just parsing the raw GETINFO response to cut startup time down.
        #
        # Only fetching this if our cache is at least an hour old (and hence a new
        # consensus available).

        cache_age = time.time() - nyx.cache().relays_updated_at()
        controller = tor_controller()

        if cache_age < 3600:
            stem.util.log.info('Cache is only %s old, no need to refresh it.' %
                               str_tools.time_label(cache_age, is_long=True))
        else:
            stem.util.log.info(
                'Cache is %s old, refreshing relay information.' %
                str_tools.time_label(cache_age, is_long=True))
            ns_response = controller.get_info('ns/all', None)

            if ns_response:
                self._update(ns_response)

        controller.add_event_listener(
            lambda event: self._update(event.consensus_content),
            stem.control.EventType.NEWCONSENSUS)
Ejemplo n.º 2
0
  def __init__(self, clone = None):
    GraphCategory.__init__(self, clone)
    self._title_last_updated = None

    if not clone:
      # fill in past bandwidth information

      controller = tor_controller()
      bw_entries, is_successful = controller.get_info('bw-event-cache', None), True

      if bw_entries:
        for entry in bw_entries.split():
          entry_comp = entry.split(',')

          if len(entry_comp) != 2 or not entry_comp[0].isdigit() or not entry_comp[1].isdigit():
            log.warn("Tor's 'GETINFO bw-event-cache' provided malformed output: %s" % bw_entries)
            is_successful = False
            break

          self.primary.update(int(entry_comp[0]))
          self.secondary.update(int(entry_comp[1]))

        if is_successful:
          log.info('Bandwidth graph has information for the last %s' % str_tools.time_label(len(bw_entries.split()), is_long = True))

      read_total = controller.get_info('traffic/read', None)
      write_total = controller.get_info('traffic/written', None)
      start_time = system.start_time(controller.get_pid(None))

      if read_total and write_total and start_time:
        self.primary.total = int(read_total)
        self.secondary.total = int(write_total)
        self.start_time = start_time
Ejemplo n.º 3
0
def _x_axis_labels(interval, columns):
  """
  Provides the labels for the x-axis. We include the units for only its first
  value, then bump the precision for subsequent units. For example...

    10s, 20, 30, 40, 50, 1m, 1.1, 1.3, 1.5
  """

  x_axis_labels = {}

  interval_sec = INTERVAL_SECONDS[interval]
  interval_spacing = 10 if columns >= WIDE_LABELING_GRAPH_COL else 5
  previous_units, decimal_precision = None, 0

  for i in range((columns - 4) // interval_spacing):
    x = (i + 1) * interval_spacing
    time_label = str_tools.time_label(x * interval_sec, decimal_precision)

    if not previous_units:
      previous_units = time_label[-1]
    elif previous_units != time_label[-1]:
      previous_units = time_label[-1]
      decimal_precision = 1  # raised precision for future measurements
    else:
      time_label = time_label[:-1]  # strip units since already provided

    x_axis_labels[x] = time_label

  return x_axis_labels
Ejemplo n.º 4
0
def _x_axis_labels(interval, columns):
  """
  Provides the labels for the x-axis. We include the units for only its first
  value, then bump the precision for subsequent units. For example...

    10s, 20, 30, 40, 50, 1m, 1.1, 1.3, 1.5
  """

  x_axis_labels = {}

  interval_sec = INTERVAL_SECONDS[interval]
  interval_spacing = 10 if columns >= WIDE_LABELING_GRAPH_COL else 5
  previous_units, decimal_precision = None, 0

  for i in range((columns - 4) / interval_spacing):
    x = (i + 1) * interval_spacing
    time_label = str_tools.time_label(x * interval_sec, decimal_precision)

    if not previous_units:
      previous_units = time_label[-1]
    elif previous_units != time_label[-1]:
      previous_units = time_label[-1]
      decimal_precision = 1  # raised precision for future measurements
    else:
      time_label = time_label[:-1]  # strip units since already provided

    x_axis_labels[x] = time_label

  return x_axis_labels
Ejemplo n.º 5
0
  def _get_x_axis_labels(self, attr, subgraph_columns):
    """
    Provides the labels for the x-axis. We include the units for only its first
    value, then bump the precision for subsequent units. For example...

      10s, 20, 30, 40, 50, 1m, 1.1, 1.3, 1.5
    """

    x_axis_labels = {}

    interval_sec = INTERVAL_SECONDS[attr.interval]
    interval_spacing = 10 if subgraph_columns >= WIDE_LABELING_GRAPH_COL else 5
    units_label, decimal_precision = None, 0

    for i in range((subgraph_columns - 4) / interval_spacing):
      x = (i + 1) * interval_spacing
      time_label = str_tools.time_label(x * interval_sec, decimal_precision)

      if not units_label:
        units_label = time_label[-1]
      elif units_label != time_label[-1]:
        # upped scale so also up precision of future measurements
        units_label = time_label[-1]
        decimal_precision += 1
      else:
        # if constrained on space then strips labeling since already provided
        time_label = time_label[:-1]

      x_axis_labels[x] = time_label

    return x_axis_labels
Ejemplo n.º 6
0
  def __init__(self, clone = None):
    GraphCategory.__init__(self, clone)

    if not clone:
      # fill in past bandwidth information

      controller = tor_controller()
      bw_entries, is_successful = controller.get_info('bw-event-cache', None), True

      if bw_entries:
        for entry in bw_entries.split():
          entry_comp = entry.split(',')

          if len(entry_comp) != 2 or not entry_comp[0].isdigit() or not entry_comp[1].isdigit():
            log.warn(msg('panel.graphing.bw_event_cache_malformed', response = bw_entries))
            is_successful = False
            break

          self.primary.update(int(entry_comp[0]))
          self.secondary.update(int(entry_comp[1]))

        if is_successful:
          log.info(msg('panel.graphing.prepopulation_successful', duration = str_tools.time_label(len(bw_entries.split()), is_long = True)))

      read_total = controller.get_info('traffic/read', None)
      write_total = controller.get_info('traffic/written', None)
      start_time = system.start_time(controller.get_pid(None))

      if read_total and write_total and start_time:
        self.primary.total = int(read_total)
        self.secondary.total = int(write_total)
        self.start_time = start_time
Ejemplo n.º 7
0
  def test_time_label(self):
    """
    Checks the time_label() function.
    """

    # test the pydoc examples
    self.assertEqual('2h', str_tools.time_label(10000))
    self.assertEqual('1.0 minute', str_tools.time_label(61, 1, True))
    self.assertEqual('1.01 minutes', str_tools.time_label(61, 2, True))

    self.assertEqual('0s', str_tools.time_label(0))
    self.assertEqual('0s', str_tools.time_label(0.1))
    self.assertEqual('0 seconds', str_tools.time_label(0, is_long = True))
    self.assertEqual('0.00s', str_tools.time_label(0, 2))
    self.assertEqual('0.10s', str_tools.time_label(0.1, 2))
    self.assertEqual('-10s', str_tools.time_label(-10))

    self.assertRaises(TypeError, str_tools.time_label, None)
    self.assertRaises(TypeError, str_tools.time_label, 'hello world')
Ejemplo n.º 8
0
  def test_time_label(self):
    """
    Checks the time_label() function.
    """

    # test the pydoc examples
    self.assertEqual('2h', str_tools.time_label(10000))
    self.assertEqual('1.0 minute', str_tools.time_label(61, 1, True))
    self.assertEqual('1.01 minutes', str_tools.time_label(61, 2, True))

    self.assertEqual('0s', str_tools.time_label(0))
    self.assertEqual('0 seconds', str_tools.time_label(0, is_long = True))
    self.assertEqual('0.00s', str_tools.time_label(0, 2))
    self.assertEqual('-10s', str_tools.time_label(-10))

    self.assertRaises(TypeError, str_tools.time_label, None)
    self.assertRaises(TypeError, str_tools.time_label, 'hello world')
Ejemplo n.º 9
0
    def value(self):
        """
    Provides the value of this configuration option.

    :returns: **str** representation of the current config value
    """

        values = tor_controller().get_conf(self.name, [], True)

        if not values:
            return '<none>'
        elif self.value_type == 'Boolean' and values[0] in ('0', '1'):
            return 'False' if values[0] == '0' else 'True'
        elif self.value_type == 'DataSize' and values[0].isdigit():
            return str_tools.size_label(int(values[0]))
        elif self.value_type == 'TimeInterval' and values[0].isdigit():
            return str_tools.time_label(int(values[0]), is_long=True)
        else:
            return ', '.join(values)
Ejemplo n.º 10
0
def _draw_right_column(subwindow, x, y, line, current_time, attr):
  if line.line_type == LineType.CIRCUIT:
    circ_path = [fp for fp, _ in line.circuit.path]
    circ_index = circ_path.index(line.fingerprint)

    if circ_index == len(circ_path) - 1:
      placement_type = 'Exit' if line.circuit.status == 'BUILT' else 'Extending'
    elif circ_index == 0:
      placement_type = 'Guard'
    else:
      placement_type = 'Middle'

    subwindow.addstr(x + 4, y, '%i / %s' % (circ_index + 1, placement_type), *attr)
  else:
    x = subwindow.addstr(x, y, '+' if line.connection.is_legacy else ' ', *attr)
    x = subwindow.addstr(x, y, '%5s' % str_tools.time_label(current_time - line.connection.start_time, 1), *attr)
    x = subwindow.addstr(x, y, ' (', *attr)
    x = subwindow.addstr(x, y, line.entry.get_type().upper(), BOLD, *attr)
    x = subwindow.addstr(x, y, ')', *attr)
Ejemplo n.º 11
0
  def value(self):
    """
    Provides the value of this configuration option.

    :returns: **str** representation of the current config value
    """

    values = tor_controller().get_conf(self.name, [], True)

    if not values:
      return '<none>'
    elif self.value_type == 'Boolean' and values[0] in ('0', '1'):
      return 'False' if values[0] == '0' else 'True'
    elif self.value_type == 'DataSize' and values[0].isdigit():
      return str_tools.size_label(int(values[0]))
    elif self.value_type == 'TimeInterval' and values[0].isdigit():
      return str_tools.time_label(int(values[0]), is_long = True)
    else:
      return ', '.join(values)
Ejemplo n.º 12
0
def _draw_right_column(subwindow, x, y, line, current_time, attr):
  if line.line_type == LineType.CIRCUIT:
    circ_path = [fp for fp, _ in line.circuit.path]
    circ_index = circ_path.index(line.fingerprint)

    if circ_index == len(circ_path) - 1:
      placement_type = 'End' if line.circuit.status == 'BUILT' else 'Extending'
    elif circ_index == 0:
      placement_type = 'Guard'
    else:
      placement_type = 'Middle'

    subwindow.addstr(x + 4, y, '%i / %s' % (circ_index + 1, placement_type), *attr)
  else:
    x = subwindow.addstr(x, y, '+' if line.connection.is_legacy else ' ', *attr)
    x = subwindow.addstr(x, y, '%5s' % str_tools.time_label(current_time - line.connection.start_time, 1), *attr)
    x = subwindow.addstr(x, y, ' (', *attr)
    x = subwindow.addstr(x, y, line.entry.get_type().upper(), BOLD, *attr)
    x = subwindow.addstr(x, y, ')', *attr)
Ejemplo n.º 13
0
  def _get_value(self):
    """
    Provides the current value of the configuration entry, taking advantage of
    the tor_tools caching to effectively query the accurate value. This uses the
    value's type to provide a user friendly representation if able.
    """

    conf_value = ', '.join(tor_controller().get_conf(self.get(Field.OPTION), [], True))

    # provides nicer values for recognized types

    if not conf_value:
      conf_value = '<none>'
    elif self.get(Field.TYPE) == 'Boolean' and conf_value in ('0', '1'):
      conf_value = 'False' if conf_value == '0' else 'True'
    elif self.get(Field.TYPE) == 'DataSize' and conf_value.isdigit():
      conf_value = str_tools.size_label(int(conf_value))
    elif self.get(Field.TYPE) == 'TimeInterval' and conf_value.isdigit():
      conf_value = str_tools.time_label(int(conf_value), is_long = True)

    return conf_value
Ejemplo n.º 14
0
    def __init__(self, clone=None):
        GraphCategory.__init__(self, clone)

        if not clone:
            # fill in past bandwidth information

            controller = tor_controller()
            bw_entries, is_successful = controller.get_info(
                'bw-event-cache', None), True

            if bw_entries:
                for entry in bw_entries.split():
                    entry_comp = entry.split(',')

                    if len(entry_comp) != 2 or not entry_comp[0].isdigit(
                    ) or not entry_comp[1].isdigit():
                        log.warn(
                            msg('panel.graphing.bw_event_cache_malformed',
                                response=bw_entries))
                        is_successful = False
                        break

                    self.primary.update(int(entry_comp[0]))
                    self.secondary.update(int(entry_comp[1]))

                if is_successful:
                    log.info(
                        msg('panel.graphing.prepopulation_successful',
                            duration=str_tools.time_label(len(
                                bw_entries.split()),
                                                          is_long=True)))

            read_total = controller.get_info('traffic/read', None)
            write_total = controller.get_info('traffic/written', None)
            start_time = system.start_time(controller.get_pid(None))

            if read_total and write_total and start_time:
                self.primary.total = int(read_total)
                self.secondary.total = int(write_total)
                self.start_time = start_time
Ejemplo n.º 15
0
    def _Config_DropDown(self):
        for line in self.controller.get_info('config/names').splitlines():
            line_comp = line.split()
            name, value_type = line_comp[0], line_comp[1]
            values = self.controller.get_conf(name, [], True)

            if not values:
                Config = '<none>'
            elif value_type == 'Boolean' and values[0] in ('0', '1'):
                if values[0] == '0':
                    Config = 'False'
                else:
                    Config = 'True'
            elif value_type == 'DataSize' and values[0].isdigit():
                Config = str_tools.size_label(int(values[0]))
            elif value_type == 'TimeInterval' and values[0].isdigit():
                Config = str_tools.time_label(int(values[0]), is_long=True)
            else:
                Config = values[0]
            Value_Type.update({name: value_type})
            Configurations.update({name: Config})
            self.ui.Config_Options.addItem(name)
        self._Config_CurrentVal()
Ejemplo n.º 16
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
  """

  controller = tor_controller()
  custom_options = get_custom_options()
  issues_found, seen_options = [], []

  # Strips comments and collapses multiline multi-line entries, for more
  # information see:
  # https://trac.torproject.org/projects/tor/ticket/1929

  stripped_contents, multiline_buffer = [], ''

  for line in _strip_comments(contents):
    if not line:
      stripped_contents.append('')
    else:
      line = multiline_buffer + line
      multiline_buffer = ''

      if line.endswith('\\'):
        multiline_buffer = line[:-1]
        stripped_contents.append('')
      else:
        stripped_contents.append(line.strip())

  for line_number in range(len(stripped_contents) - 1, -1, -1):
    line_text = stripped_contents[line_number]

    if not line_text:
      continue

    line_comp = line_text.split(None, 1)

    if len(line_comp) == 2:
      option, value = line_comp
    else:
      option, value = line_text, ''

    # 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 custom_options 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 custom_opt in custom_options:
      if custom_opt.lower() == option.lower():
        option = custom_opt
        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 seen_options and option not in get_multiline_parameters():
      issues_found.append((line_number, ValidationError.DUPLICATE, option))
      continue
    else:
      seen_options.append(option)

    # checks if the value isn't necessary due to matching the defaults

    if option not in custom_options:
      issues_found.append((line_number, 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, value_type = _parse_conf_value(value)

    # issues GETCONF to get the values tor's currently configured to use

    tor_values = controller.get_conf(option, [], True)

    # multiline entries can be comma separated values (for both tor and conf)

    value_list = [value]

    if option in get_multiline_parameters():
      value_list = [val.strip() for val in value.split(',')]

      fetched_values, tor_values = tor_values, []
      for fetched_value in fetched_values:
        for fetched_entry in fetched_value.split(','):
          fetched_entry = fetched_entry.strip()

          if fetched_entry not in tor_values:
            tor_values.append(fetched_entry)

    for val in value_list:
      # checks if both the argument and tor's value are empty

      is_blank_match = not val and not tor_values

      if not is_blank_match and val not in tor_values:
        # converts corrections to reader friedly size values

        display_values = tor_values

        if value_type == ValueType.SIZE:
          display_values = [str_tools.size_label(int(val)) for val in tor_values]
        elif value_type == ValueType.TIME:
          display_values = [str_tools.time_label(int(val)) for val in tor_values]

        issues_found.append((line_number, ValidationError.MISMATCH, ', '.join(display_values)))

  # checks if any custom options are missing from the torrc

  for option in custom_options:
    # 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 option not in seen_options:
      issues_found.append((None, ValidationError.MISSING, option))

  return issues_found