Ejemplo n.º 1
0
    def _update(self):
        self._vals = Sampling.create(self._vals)

        if self._vals.fd_used and self._vals.fd_limit != -1:
            fd_percent = 100 * self._vals.fd_used // self._vals.fd_limit

            if fd_percent >= 90:
                log_msg = "Tor's file descriptor usage is at %s%%. If you run out Tor will be unable to continue functioning." % fd_percent
                log.log_once('fd_used_at_ninety_percent', log.WARN, log_msg)
                log.DEDUPLICATION_MESSAGE_IDS.add('fd_used_at_sixty_percent')
            elif fd_percent >= 60:
                log_msg = "Tor's file descriptor usage is at %s%%." % fd_percent
                log.log_once('fd_used_at_sixty_percent', log.NOTICE, log_msg)

        if self._vals.is_connected:
            if not self._reported_inactive and (
                    time.time() - self._vals.last_heartbeat) >= 10:
                self._reported_inactive = True
                log.notice('Relay unresponsive (last heartbeat: %s)' %
                           time.ctime(self._vals.last_heartbeat))
            elif self._reported_inactive and (time.time() -
                                              self._vals.last_heartbeat) < 10:
                self._reported_inactive = False
                log.notice('Relay resumed')

        self.redraw()
Ejemplo n.º 2
0
    def _update(self):
        self._vals = Sampling.create(self._vals)

        if self._vals.fd_used and self._vals.fd_limit != -1:
            fd_percent = 100 * self._vals.fd_used / self._vals.fd_limit

            if fd_percent >= 90:
                log_msg = msg('panel.header.fd_used_at_ninety_percent',
                              percentage=fd_percent)
                log.log_once('fd_used_at_ninety_percent', log.WARN, log_msg)
                log.DEDUPLICATION_MESSAGE_IDS.add('fd_used_at_sixty_percent')
            elif fd_percent >= 60:
                log_msg = msg('panel.header.fd_used_at_sixty_percent',
                              percentage=fd_percent)
                log.log_once('fd_used_at_sixty_percent', log.NOTICE, log_msg)

        if self._vals.is_connected:
            if not self._reported_inactive and (
                    time.time() - self._vals.last_heartbeat) >= 10:
                self._reported_inactive = True
                log.notice('Relay unresponsive (last heartbeat: %s)' %
                           time.ctime(self._vals.last_heartbeat))
            elif self._reported_inactive and (time.time() -
                                              self._vals.last_heartbeat) < 10:
                self._reported_inactive = False
                log.notice('Relay resumed')

        self.redraw()
Ejemplo n.º 3
0
def is_crypto_available():
    """
  Checks if the cryptography functions we use are available. This is used for
  verifying relay descriptor signatures.

  :returns: **True** if we can use the cryptography module and **False**
    otherwise
  """

    try:
        from cryptography.utils import int_from_bytes, int_to_bytes
        from cryptography.hazmat.backends import default_backend
        from cryptography.hazmat.primitives.asymmetric import rsa
        from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
        from cryptography.hazmat.primitives.serialization import load_der_public_key

        if not hasattr(rsa.RSAPrivateKey, 'sign'):
            raise ImportError()

        return True
    except ImportError:
        from stem.util import log
        log.log_once('stem.prereq.is_crypto_available', log.INFO,
                     CRYPTO_UNAVAILABLE)
        return False
Ejemplo n.º 4
0
    def get_value(self, key, default=None, multiple=False):
        """
    This provides the current value associated with a given key.

    :param str key: config setting to be fetched
    :param object default: value provided if no such key exists
    :param bool multiple: provides back a list of all values if **True**,
      otherwise this returns the last loaded configuration value

    :returns: **str** or **list** of string configuration values associated
      with the given key, providing the default if no such key exists
    """

        with self._contents_lock:
            if key in self._contents:
                self._requested_keys.add(key)

                if multiple:
                    return self._contents[key]
                else:
                    return self._contents[key][-1]
            else:
                message_id = 'stem.util.conf.missing_config_key_%s' % key
                log.log_once(
                    message_id, log.TRACE,
                    "config entry '%s' not found, defaulting to '%s'" %
                    (key, default))
                return default
Ejemplo n.º 5
0
Archivo: conf.py Proyecto: arlolra/stem
  def get_value(self, key, default = None, multiple = False):
    """
    This provides the current value associated with a given key.

    :param str key: config setting to be fetched
    :param object default: value provided if no such key exists
    :param bool multiple: provides back a list of all values if **True**,
      otherwise this returns the last loaded configuration value

    :returns: **str** or **list** of string configuration values associated
      with the given key, providing the default if no such key exists
    """

    with self._contents_lock:
      if key in self._contents:
        self._requested_keys.add(key)

        if multiple:
          return self._contents[key]
        else:
          return self._contents[key][-1]
      else:
        message_id = "stem.util.conf.missing_config_key_%s" % key
        log.log_once(message_id, log.TRACE, "config entry '%s' not found, defaulting to '%s'" % (key, default))
        return default
Ejemplo n.º 6
0
Archivo: prereq.py Proyecto: soult/stem
def is_crypto_available():
  """
  Checks if the pycrypto functions we use are available.

  :returns: **True** if we can use pycrypto and **False** otherwise
  """

  global IS_CRYPTO_AVAILABLE

  if IS_CRYPTO_AVAILABLE is None:
    from stem.util import log

    try:
      from Crypto.PublicKey import RSA
      from Crypto.Util import asn1
      from Crypto.Util.number import long_to_bytes
      IS_CRYPTO_AVAILABLE = True
    except ImportError:
      IS_CRYPTO_AVAILABLE = False

      # the code that verifies relay descriptor signatures uses the python-crypto library
      msg = "Unable to import the pycrypto module. Because of this we'll be unable to verify descriptor signature integrity. You can get pycrypto from: https://www.dlitz.net/software/pycrypto/"
      log.log_once("stem.prereq.is_crypto_available", log.INFO, msg)

  return IS_CRYPTO_AVAILABLE
Ejemplo n.º 7
0
def is_crypto_available():
  """
  Checks if the pycrypto functions we use are available.

  :returns: **True** if we can use pycrypto and **False** otherwise
  """

  global IS_CRYPTO_AVAILABLE

  if IS_CRYPTO_AVAILABLE is None:
    from stem.util import log

    try:
      from Crypto.PublicKey import RSA
      from Crypto.Util import asn1
      from Crypto.Util.number import long_to_bytes
      IS_CRYPTO_AVAILABLE = True
    except ImportError:
      IS_CRYPTO_AVAILABLE = False

      # the code that verifies relay descriptor signatures uses the python-crypto library
      msg = "Unable to import the pycrypto module. Because of this we'll be unable to verify descriptor signature integrity. You can get pycrypto from: https://www.dlitz.net/software/pycrypto/"
      log.log_once("stem.prereq.is_crypto_available", log.INFO, msg)

  return IS_CRYPTO_AVAILABLE
Ejemplo n.º 8
0
def is_rsa_available():
  global IS_RSA_AVAILABLE
  
  if IS_RSA_AVAILABLE == None:
    try:
      import rsa
      IS_RSA_AVAILABLE = True
    except ImportError:
      IS_RSA_AVAILABLE = False
      
      msg = "Unable to import the rsa module. Because of this we'll be unable to verify descriptor signature integrity."
      log.log_once("stem.prereq.is_rsa_available", log.INFO, msg)
  
  return IS_RSA_AVAILABLE
Ejemplo n.º 9
0
def is_crypto_available():
    global IS_CRYPTO_AVAILABLE

    if IS_CRYPTO_AVAILABLE is None:
        try:
            from Crypto.PublicKey import RSA
            from Crypto.Util import asn1
            from Crypto.Util.number import long_to_bytes
            IS_CRYPTO_AVAILABLE = True
        except ImportError:
            IS_CRYPTO_AVAILABLE = False

            # the code that verifies relay descriptor signatures uses the python-crypto library
            msg = "Unable to import the crypto module. Because of this we'll be unable to verify descriptor signature integrity."
            log.log_once("stem.prereq.is_crypto_available", log.INFO, msg)

    return IS_CRYPTO_AVAILABLE
Ejemplo n.º 10
0
def is_lzma_available():
  """
  Checks if the `lzma module <https://docs.python.org/3/library/lzma.html>`_ is
  available. This was added as a builtin in Python 3.3.

  .. versionadded:: 1.7.0

  :returns: **True** if we can use the lzma module and **False** otherwise
  """

  try:
    import lzma
    return True
  except ImportError:
    from stem.util import log
    log.log_once('stem.prereq.is_lzma_available', log.INFO, LZMA_UNAVAILABLE)
    return False
Ejemplo n.º 11
0
def _is_pynacl_available():
  """
  Checks if the pynacl functions we use are available. This is used for
  verifying ed25519 certificates in relay descriptor signatures.

  :returns: **True** if we can use pynacl and **False** otherwise
  """

  from stem.util import log

  try:
    from nacl import encoding
    from nacl import signing
    return True
  except ImportError:
    log.log_once('stem.prereq._is_pynacl_available', log.INFO, PYNACL_UNAVAILABLE)
    return False
Ejemplo n.º 12
0
def is_crypto_available():
  global IS_CRYPTO_AVAILABLE
  
  if IS_CRYPTO_AVAILABLE is None:
    try:
      from Crypto.PublicKey import RSA
      from Crypto.Util import asn1
      from Crypto.Util.number import long_to_bytes
      IS_CRYPTO_AVAILABLE = True
    except ImportError:
      IS_CRYPTO_AVAILABLE = False
      
      # the code that verifies relay descriptor signatures uses the python-crypto library
      msg = "Unable to import the crypto module. Because of this we'll be unable to verify descriptor signature integrity."
      log.log_once("stem.prereq.is_crypto_available", log.INFO, msg)
  
  return IS_CRYPTO_AVAILABLE
Ejemplo n.º 13
0
def is_crypto_available():
  """
  Checks if the pycrypto functions we use are available. This is used for
  verifying relay descriptor signatures.

  :returns: **True** if we can use pycrypto and **False** otherwise
  """

  from stem.util import log

  try:
    from Crypto.PublicKey import RSA
    from Crypto.Util import asn1
    from Crypto.Util.number import long_to_bytes
    return True
  except ImportError:
    log.log_once('stem.prereq.is_crypto_available', log.INFO, CRYPTO_UNAVAILABLE)
    return False
Ejemplo n.º 14
0
  def _log_if_unrecognized(self, attr, attr_enum):
    """
    Checks if an attribute exists in a given enumeration, logging a message if
    it isn't. Attributes can either be for a string or collection of strings

    :param str attr: name of the attribute to check
    :param stem.util.enum.Enum enum: enumeration to check against
    """

    attr_values = getattr(self, attr)

    if attr_values:
      if isinstance(attr_values, (bytes, unicode)):
        attr_values = [attr_values]

      for value in attr_values:
        if not value in attr_enum:
          log_id = "event.%s.unknown_%s.%s" % (self.type.lower(), attr, value)
          unrecognized_msg = "%s event had an unrecognized %s (%s). Maybe a new addition to the control protocol? Full Event: '%s'" % (self.type, attr, value, self)
          log.log_once(log_id, log.INFO, unrecognized_msg)
Ejemplo n.º 15
0
  def _log_if_unrecognized(self, attr, attr_enum):
    """
    Checks if an attribute exists in a given enumeration, logging a message if
    it isn't. Attributes can either be for a string or collection of strings

    :param str attr: name of the attribute to check
    :param stem.util.enum.Enum enum: enumeration to check against
    """

    attr_values = getattr(self, attr)

    if attr_values:
      if isinstance(attr_values, (bytes, unicode)):
        attr_values = [attr_values]

      for value in attr_values:
        if not value in attr_enum:
          log_id = "event.%s.unknown_%s.%s" % (self.type.lower(), attr, value)
          unrecognized_msg = "%s event had an unrecognized %s (%s). Maybe a new addition to the control protocol? Full Event: '%s'" % (self.type, attr, value, self)
          log.log_once(log_id, log.INFO, unrecognized_msg)
Ejemplo n.º 16
0
def is_zstd_available():
  """
  Checks if the `zstd module <https://pypi.org/project/zstandard/>`_ is
  available.

  .. versionadded:: 1.7.0

  :returns: **True** if we can use the zstd module and **False** otherwise
  """

  try:
    # Unfortunately the zstandard module uses the same namespace as another
    # zstd module (https://pypi.org/project/zstd/), so we need to
    # differentiate them.

    import zstd
    return hasattr(zstd, 'ZstdDecompressor')
  except ImportError:
    from stem.util import log
    log.log_once('stem.prereq.is_zstd_available', log.INFO, ZSTD_UNAVAILABLE)
    return False
Ejemplo n.º 17
0
def _is_crypto_ed25519_supported():
    """
  Checks if ed25519 is supported by current versions of the cryptography
  package and OpenSSL. This is used for verifying ed25519 certificates in relay
  descriptor signatures.

  :returns: **True** if ed25519 is supported and **False** otherwise
  """

    if not is_crypto_available():
        return False

    from stem.util import log
    from cryptography.hazmat.backends.openssl.backend import backend

    if hasattr(backend, 'ed25519_supported') and backend.ed25519_supported():
        return True
    else:
        log.log_once('stem.prereq._is_crypto_ed25519_supported', log.INFO,
                     ED25519_UNSUPPORTED)
        return False
Ejemplo n.º 18
0
def is_crypto_available(ed25519 = False):
  """
  Checks if the cryptography functions we use are available. This is used for
  verifying relay descriptor signatures.

  :param bool ed25519: check for `ed25519 support
    <https://cryptography.io/en/latest/hazmat/primitives/asymmetric/ed25519/>`_,
    which requires both cryptography version 2.6 and OpenSSL support

  :returns: **True** if we can use the cryptography module and **False**
    otherwise
  """

  from stem.util import log

  try:
    from cryptography.utils import int_from_bytes, int_to_bytes
    from cryptography.hazmat.backends import default_backend
    from cryptography.hazmat.backends.openssl.backend import backend
    from cryptography.hazmat.primitives.asymmetric import rsa
    from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
    from cryptography.hazmat.primitives.serialization import load_der_public_key

    if not hasattr(rsa.RSAPrivateKey, 'sign'):
      raise ImportError()

    if ed25519:
      # The following import confirms cryptography support (ie. version 2.6+),
      # whereas ed25519_supported() checks for OpenSSL bindings.

      from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey

      if not hasattr(backend, 'ed25519_supported') or not backend.ed25519_supported():
        log.log_once('stem.prereq._is_crypto_ed25519_supported', log.INFO, ED25519_UNSUPPORTED)
        return False

    return True
  except ImportError:
    log.log_once('stem.prereq.is_crypto_available', log.INFO, CRYPTO_UNAVAILABLE)
    return False
Ejemplo n.º 19
0
  def _update(self):
    self._vals = Sampling.create(self._vals)

    if self._vals.fd_used and self._vals.fd_limit != -1:
      fd_percent = 100 * self._vals.fd_used / self._vals.fd_limit

      if fd_percent >= 90:
        log_msg = msg('panel.header.fd_used_at_ninety_percent', percentage = fd_percent)
        log.log_once('fd_used_at_ninety_percent', log.WARN, log_msg)
        log.DEDUPLICATION_MESSAGE_IDS.add('fd_used_at_sixty_percent')
      elif fd_percent >= 60:
        log_msg = msg('panel.header.fd_used_at_sixty_percent', percentage = fd_percent)
        log.log_once('fd_used_at_sixty_percent', log.NOTICE, log_msg)

    if self._vals.is_connected:
      if not self._reported_inactive and (time.time() - self._vals.last_heartbeat) >= 10:
        self._reported_inactive = True
        log.notice('Relay unresponsive (last heartbeat: %s)' % time.ctime(self._vals.last_heartbeat))
      elif self._reported_inactive and (time.time() - self._vals.last_heartbeat) < 10:
        self._reported_inactive = False
        log.notice('Relay resumed')

    self.redraw()
Ejemplo n.º 20
0
  def _update(self):
    previous_height = self.get_height()
    self._vals = get_sampling(self._vals)

    if self._vals.fd_used and self._vals.fd_limit != -1:
      fd_percent = 100 * self._vals.fd_used / self._vals.fd_limit

      if fd_percent >= 90:
        log_msg = msg('panel.header.fd_used_at_ninety_percent', percentage = fd_percent)
        log.log_once('fd_used_at_ninety_percent', log.WARN, log_msg)
        log.DEDUPLICATION_MESSAGE_IDS.add('fd_used_at_sixty_percent')
      elif fd_percent >= 60:
        log_msg = msg('panel.header.fd_used_at_sixty_percent', percentage = fd_percent)
        log.log_once('fd_used_at_sixty_percent', log.NOTICE, log_msg)

    if previous_height != self.get_height():
      # We're toggling between being a relay and client, causing the height
      # of this panel to change. Redraw all content so we don't get
      # overlapping content.

      nyx.controller.get_controller().redraw()
    else:
      self.redraw(True)  # just need to redraw ourselves
Ejemplo n.º 21
0
  def _parse_message(self):
    # Example:
    #   250-PROTOCOLINFO 1
    #   250-AUTH METHODS=COOKIE COOKIEFILE="/home/atagar/.tor/control_auth_cookie"
    #   250-VERSION Tor="0.2.1.30"
    #   250 OK

    self.protocol_version = None
    self.tor_version = None
    self.auth_methods = ()
    self.unknown_auth_methods = ()
    self.cookie_path = None

    auth_methods, unknown_auth_methods = [], []
    remaining_lines = list(self)

    if not self.is_ok() or not remaining_lines.pop() == "OK":
      raise stem.ProtocolError("PROTOCOLINFO response didn't have an OK status:\n%s" % self)

    # sanity check that we're a PROTOCOLINFO response
    if not remaining_lines[0].startswith("PROTOCOLINFO"):
      raise stem.ProtocolError("Message is not a PROTOCOLINFO response:\n%s" % self)

    while remaining_lines:
      line = remaining_lines.pop(0)
      line_type = line.pop()

      if line_type == "PROTOCOLINFO":
        # Line format:
        #   FirstLine = "PROTOCOLINFO" SP PIVERSION CRLF
        #   PIVERSION = 1*DIGIT

        if line.is_empty():
          raise stem.ProtocolError("PROTOCOLINFO response's initial line is missing the protocol version: %s" % line)

        try:
          self.protocol_version = int(line.pop())
        except ValueError:
          raise stem.ProtocolError("PROTOCOLINFO response version is non-numeric: %s" % line)

        # The piversion really should be "1" but, according to the spec, tor
        # does not necessarily need to provide the PROTOCOLINFO version that we
        # requested. Log if it's something we aren't expecting but still make
        # an effort to parse like a v1 response.

        if self.protocol_version != 1:
          log.info("We made a PROTOCOLINFO version 1 query but got a version %i response instead. We'll still try to use it, but this may cause problems." % self.protocol_version)
      elif line_type == "AUTH":
        # Line format:
        #   AuthLine = "250-AUTH" SP "METHODS=" AuthMethod *("," AuthMethod)
        #              *(SP "COOKIEFILE=" AuthCookieFile) CRLF
        #   AuthMethod = "NULL" / "HASHEDPASSWORD" / "COOKIE"
        #   AuthCookieFile = QuotedString

        # parse AuthMethod mapping
        if not line.is_next_mapping("METHODS"):
          raise stem.ProtocolError("PROTOCOLINFO response's AUTH line is missing its mandatory 'METHODS' mapping: %s" % line)

        for method in line.pop_mapping()[1].split(","):
          if method == "NULL":
            auth_methods.append(AuthMethod.NONE)
          elif method == "HASHEDPASSWORD":
            auth_methods.append(AuthMethod.PASSWORD)
          elif method == "COOKIE":
            auth_methods.append(AuthMethod.COOKIE)
          elif method == "SAFECOOKIE":
            auth_methods.append(AuthMethod.SAFECOOKIE)
          else:
            unknown_auth_methods.append(method)
            message_id = "stem.response.protocolinfo.unknown_auth_%s" % method
            log.log_once(message_id, log.INFO, "PROTOCOLINFO response included a type of authentication that we don't recognize: %s" % method)

            # our auth_methods should have a single AuthMethod.UNKNOWN entry if
            # any unknown authentication methods exist
            if not AuthMethod.UNKNOWN in auth_methods:
              auth_methods.append(AuthMethod.UNKNOWN)

        # parse optional COOKIEFILE mapping (quoted and can have escapes)
        if line.is_next_mapping("COOKIEFILE", True, True):
          self.cookie_path = line.pop_mapping(True, True)[1]
      elif line_type == "VERSION":
        # Line format:
        #   VersionLine = "250-VERSION" SP "Tor=" TorVersion OptArguments CRLF
        #   TorVersion = QuotedString

        if not line.is_next_mapping("Tor", True):
          raise stem.ProtocolError("PROTOCOLINFO response's VERSION line is missing its mandatory tor version mapping: %s" % line)

        try:
          self.tor_version = stem.version.Version(line.pop_mapping(True)[1])
        except ValueError as exc:
          raise stem.ProtocolError(exc)
      else:
        log.debug("Unrecognized PROTOCOLINFO line type '%s', ignoring it: %s" % (line_type, line))

    self.auth_methods = tuple(auth_methods)
    self.unknown_auth_methods = tuple(unknown_auth_methods)