Esempio n. 1
0
def _parse_or_address_line(descriptor, entries):
    all_values = _values('or-address', entries)
    or_addresses = []

    for entry in all_values:
        line = 'or-address %s' % entry

        if ':' not in entry:
            raise ValueError('or-address line missing a colon: %s' % line)

        address, port = entry.rsplit(':', 1)

        if not stem.util.connection.is_valid_ipv4_address(
                address) and not stem.util.connection.is_valid_ipv6_address(
                    address, allow_brackets=True):
            raise ValueError('or-address line has a malformed address: %s' %
                             line)

        if not stem.util.connection.is_valid_port(port):
            raise ValueError('or-address line has a malformed port: %s' % line)

        or_addresses.append(
            (address.lstrip('[').rstrip(']'), int(port),
             stem.util.connection.is_valid_ipv6_address(address,
                                                        allow_brackets=True)))

    descriptor.or_addresses = or_addresses
Esempio n. 2
0
def _parse_m_line(descriptor, entries):
  # "m" methods 1*(algorithm "=" digest)
  # example: m 8,9,10,11,12 sha256=g1vx9si329muxV3tquWIXXySNOIwRGMeAESKs/v4DWs

  all_hashes = []

  for value in _values('m', entries):
    m_comp = value.split(' ')

    if not (descriptor.document and descriptor.document.is_vote):
      vote_status = 'vote' if descriptor.document else '<undefined document>'
      raise ValueError("%s 'm' line should only appear in votes (appeared in a %s): m %s" % (descriptor._name(), vote_status, value))
    elif len(m_comp) < 1:
      raise ValueError("%s 'm' line needs to start with a series of methods: m %s" % (descriptor._name(), value))

    try:
      methods = [int(entry) for entry in m_comp[0].split(',')]
    except ValueError:
      raise ValueError('%s microdescriptor methods should be a series of comma separated integers: m %s' % (descriptor._name(), value))

    hashes = {}

    for entry in m_comp[1:]:
      if '=' not in entry:
        raise ValueError("%s can only have a series of 'algorithm=digest' mappings after the methods: m %s" % (descriptor._name(), value))

      hash_name, digest = entry.split('=', 1)
      hashes[hash_name] = digest

    all_hashes.append((methods, hashes))

  descriptor.microdescriptor_hashes = all_hashes
Esempio n. 3
0
def _parse_a_line(descriptor: 'stem.descriptor.Descriptor',
                  entries: ENTRY_TYPE) -> None:
    # "a" SP address ":" portlist
    # example: a [2001:888:2133:0:82:94:251:204]:9001

    or_addresses = []

    for value in _values('a', entries):
        if ':' not in value:
            raise ValueError(
                "%s 'a' line must be of the form '[address]:[ports]': a %s" %
                (descriptor._name(), value))

        address, port = value.rsplit(':', 1)

        if not stem.util.connection.is_valid_ipv4_address(
                address) and not stem.util.connection.is_valid_ipv6_address(
                    address, allow_brackets=True):
            raise ValueError(
                "%s 'a' line must start with an IPv6 address: a %s" %
                (descriptor._name(), value))

        if stem.util.connection.is_valid_port(port):
            or_addresses.append((address.lstrip('[').rstrip(']'), int(port),
                                 stem.util.connection.is_valid_ipv6_address(
                                     address, allow_brackets=True)))
        else:
            raise ValueError("%s 'a' line had an invalid port (%s): a %s" %
                             (descriptor._name(), port, value))

    descriptor.or_addresses = or_addresses
Esempio n. 4
0
def _parse_or_address_line(descriptor, entries):
    all_values = _values('or-address', entries)
    or_addresses = []

    for entry in all_values:
        line = 'or-address %s' % entry

        if ':' not in entry:
            raise ValueError('or-address line missing a colon: %s' % line)

        address, port = entry.rsplit(':', 1)
        is_ipv6 = address.startswith('[') and address.endswith(']')

        if is_ipv6:
            address = address[1:-1]  # remove brackets

        if not (
            (not is_ipv6
             and stem.util.connection.is_valid_ipv4_address(address)) or
            (is_ipv6 and stem.util.connection.is_valid_ipv6_address(address))):
            raise ValueError('or-address line has a malformed address: %s' %
                             line)

        if not stem.util.connection.is_valid_port(port):
            raise ValueError('or-address line has a malformed port: %s' % line)

        or_addresses.append((address, int(port), is_ipv6))

    descriptor.or_addresses = or_addresses
Esempio n. 5
0
def _parse_or_address_line(descriptor, entries):
  all_values = _values('or-address', entries)
  or_addresses = []

  for entry in all_values:
    line = 'or-address %s' % entry

    if ':' not in entry:
      raise ValueError('or-address line missing a colon: %s' % line)

    address, port = entry.rsplit(':', 1)
    is_ipv6 = address.startswith('[') and address.endswith(']')

    if is_ipv6:
      address = address[1:-1]  # remove brackets

    if not ((not is_ipv6 and stem.util.connection.is_valid_ipv4_address(address)) or
            (is_ipv6 and stem.util.connection.is_valid_ipv6_address(address))):
      raise ValueError('or-address line has a malformed address: %s' % line)

    if not stem.util.connection.is_valid_port(port):
      raise ValueError('or-address line has a malformed port: %s' % line)

    or_addresses.append((address, int(port), is_ipv6))

  descriptor.or_addresses = or_addresses
def _parse_m_line(descriptor, entries):
  # "m" methods 1*(algorithm "=" digest)
  # example: m 8,9,10,11,12 sha256=g1vx9si329muxV3tquWIXXySNOIwRGMeAESKs/v4DWs

  all_hashes = []

  for value in _values('m', entries):
    m_comp = value.split(' ')

    if not (descriptor.document and descriptor.document.is_vote):
      vote_status = 'vote' if descriptor.document else '<undefined document>'
      raise ValueError("%s 'm' line should only appear in votes (appeared in a %s): m %s" % (descriptor._name(), vote_status, value))
    elif len(m_comp) < 1:
      raise ValueError("%s 'm' line needs to start with a series of methods: m %s" % (descriptor._name(), value))

    try:
      methods = [int(entry) for entry in m_comp[0].split(',')]
    except ValueError:
      raise ValueError('%s microdescriptor methods should be a series of comma separated integers: m %s' % (descriptor._name(), value))

    hashes = {}

    for entry in m_comp[1:]:
      if '=' not in entry:
        raise ValueError("%s can only have a series of 'algorithm=digest' mappings after the methods: m %s" % (descriptor._name(), value))

      hash_name, digest = entry.split('=', 1)
      hashes[hash_name] = digest

    all_hashes.append((methods, hashes))

  descriptor.microdescriptor_hashes = all_hashes
def _parse_a_line(descriptor, entries):
  # "a" SP address ":" portlist
  # example: a [2001:888:2133:0:82:94:251:204]:9001

  or_addresses = []

  for value in _values('a', entries):
    if ':' not in value:
      raise ValueError("%s 'a' line must be of the form '[address]:[ports]': a %s" % (descriptor._name(), value))

    address, port = value.rsplit(':', 1)
    is_ipv6 = address.startswith('[') and address.endswith(']')

    if is_ipv6:
      address = address[1:-1]  # remove brackets

    if not ((not is_ipv6 and stem.util.connection.is_valid_ipv4_address(address)) or
            (is_ipv6 and stem.util.connection.is_valid_ipv6_address(address))):
      raise ValueError("%s 'a' line must start with an IPv6 address: a %s" % (descriptor._name(), value))

    if stem.util.connection.is_valid_port(port):
      or_addresses.append((address, int(port), is_ipv6))
    else:
      raise ValueError("%s 'a' line had an invalid port (%s): a %s" % (descriptor._name(), port, value))

  descriptor.or_addresses = or_addresses
Esempio n. 8
0
def _parse_transport_line(descriptor, entries):
    # "transport" transportname address:port [arglist]
    # Everything after the transportname is scrubbed in published bridge
    # descriptors, so we'll never see it in practice.
    #
    # These entries really only make sense for bridges, but have been seen
    # on non-bridges in the wild when the relay operator configured it this
    # way.

    transports = {}

    for value in _values('transport', entries):
        name, address, port, args = None, None, None, None

        if ' ' not in value:
            # scrubbed
            name = value
        else:
            # not scrubbed
            value_comp = value.split()

            if len(value_comp) < 1:
                raise ValueError(
                    'Transport line is missing its transport name: transport %s'
                    % value)
            elif len(value_comp) < 2:
                raise ValueError(
                    'Transport line is missing its address:port value: transport %s'
                    % value)
            elif ':' not in value_comp[1]:
                raise ValueError(
                    "Transport line's address:port entry is missing a colon: transport %s"
                    % value)

            name = value_comp[0]
            address, port_str = value_comp[1].rsplit(':', 1)

            if not stem.util.connection.is_valid_ipv4_address(address) or \
                   stem.util.connection.is_valid_ipv6_address(address, allow_brackets = True):
                raise ValueError(
                    'Transport line has a malformed address: transport %s' %
                    value)
            elif not stem.util.connection.is_valid_port(port_str):
                raise ValueError(
                    'Transport line has a malformed port: transport %s' %
                    value)

            address.lstrip('[').rstrip(']')
            port = int(port_str)
            args = value_comp[2:] if len(value_comp) >= 3 else []

        transports[name] = (address, port, args)

    descriptor.transport = transports
Esempio n. 9
0
def _parse_id_line(descriptor: 'stem.descriptor.Descriptor', entries: ENTRY_TYPE) -> None:
  identities = {}

  for entry in _values('id', entries):
    entry_comp = entry.split()

    if len(entry_comp) >= 2:
      key_type, key_value = entry_comp[0], entry_comp[1]

      if key_type in identities:
        raise ValueError("There can only be one 'id' line per a key type, but '%s' appeared multiple times" % key_type)

      identities[key_type] = key_value
    else:
      raise ValueError("'id' lines should contain both the key type and digest: id %s" % entry)

  descriptor.identifiers = identities
Esempio n. 10
0
def _parse_transport_line(descriptor, entries):
  # "transport" transportname address:port [arglist]
  # Everything after the transportname is scrubbed in published bridge
  # descriptors, so we'll never see it in practice.
  #
  # These entries really only make sense for bridges, but have been seen
  # on non-bridges in the wild when the relay operator configured it this
  # way.

  transports = {}

  for value in _values('transport', entries):
    name, address, port, args = None, None, None, None

    if ' ' not in value:
      # scrubbed
      name = value
    else:
      # not scrubbed
      value_comp = value.split()

      if len(value_comp) < 1:
        raise ValueError('Transport line is missing its transport name: transport %s' % value)
      elif len(value_comp) < 2:
        raise ValueError('Transport line is missing its address:port value: transport %s' % value)
      elif ':' not in value_comp[1]:
        raise ValueError("Transport line's address:port entry is missing a colon: transport %s" % value)

      name = value_comp[0]
      address, port_str = value_comp[1].rsplit(':', 1)

      if not stem.util.connection.is_valid_ipv4_address(address) or \
             stem.util.connection.is_valid_ipv6_address(address, allow_brackets = True):
        raise ValueError('Transport line has a malformed address: transport %s' % value)
      elif not stem.util.connection.is_valid_port(port_str):
        raise ValueError('Transport line has a malformed port: transport %s' % value)

      address.lstrip('[').rstrip(']')
      port = int(port_str)
      args = value_comp[2:] if len(value_comp) >= 3 else []

    transports[name] = (address, port, args)

  descriptor.transport = transports
Esempio n. 11
0
def _parse_id_line(descriptor, entries):
  identities = {}

  for entry in _values('id', entries):
    entry_comp = entry.split()

    if len(entry_comp) >= 2:
      key_type, key_value = entry_comp[0], entry_comp[1]

      if key_type in identities:
        raise ValueError("There can only be one 'id' line per a key type, but '%s' appeared multiple times" % key_type)

      descriptor.identifier_type = key_type
      descriptor.identifier = key_value
      identities[key_type] = key_value
    else:
      raise ValueError("'id' lines should contain both the key type and digest: id %s" % entry)

  descriptor.identifiers = identities
Esempio n. 12
0
def _parse_or_address_line(descriptor, entries):
  all_values = _values('or-address', entries)
  or_addresses = []

  for entry in all_values:
    line = 'or-address %s' % entry

    if ':' not in entry:
      raise ValueError('or-address line missing a colon: %s' % line)

    address, port = entry.rsplit(':', 1)

    if not stem.util.connection.is_valid_ipv4_address(address) and not stem.util.connection.is_valid_ipv6_address(address, allow_brackets = True):
      raise ValueError('or-address line has a malformed address: %s' % line)

    if not stem.util.connection.is_valid_port(port):
      raise ValueError('or-address line has a malformed port: %s' % line)

    or_addresses.append((address.lstrip('[').rstrip(']'), int(port), stem.util.connection.is_valid_ipv6_address(address, allow_brackets = True)))

  descriptor.or_addresses = or_addresses