Beispiel #1
0
  def test_unpack_for_new_link(self):
    expected_certs = (
      (CertType.LINK, 1, b'0\x82\x02F0\x82\x01\xaf'),
      (CertType.IDENTITY, 2, b'0\x82\x01\xc90\x82\x012'),
      (CertType.UNKNOWN, 4, b'\x01\x04\x00\x06m\x1f'),
      (CertType.UNKNOWN, 5, b'\x01\x05\x00\x06m\n\x01'),
      (CertType.UNKNOWN, 7, b'\x1a\xa5\xb3\xbd\x88\xb1C'),
    )

    content = test_data('new_link_cells')

    version_cell, content = Cell.pop(content, 2)
    self.assertEqual(VersionsCell([3, 4, 5]), version_cell)

    certs_cell, content = Cell.pop(content, 2)
    self.assertEqual(CertsCell, type(certs_cell))
    self.assertEqual(len(expected_certs), len(certs_cell.certificates))

    for i, (cert_type, cert_type_int, cert_prefix) in enumerate(expected_certs):
      self.assertEqual(cert_type, certs_cell.certificates[i].type)
      self.assertEqual(cert_type_int, certs_cell.certificates[i].type_int)
      self.assertTrue(certs_cell.certificates[i].value.startswith(cert_prefix))

    auth_challenge_cell, content = Cell.pop(content, 2)
    self.assertEqual(AuthChallengeCell([1, 3], b'\x89Y\t\x99\xb2\x1e\xd9*V\xb6\x1bn\n\x05\xd8/\xe3QH\x85\x13Z\x17\xfc\x1c\x00{\xa9\xae\x83^K'), auth_challenge_cell)

    netinfo_cell, content = Cell.pop(content, 2)
    self.assertEqual(NetinfoCell, type(netinfo_cell))
    self.assertEqual(datetime.datetime(2018, 1, 14, 1, 46, 56), netinfo_cell.timestamp)
    self.assertEqual(Address('127.0.0.1'), netinfo_cell.receiver_address)
    self.assertEqual([Address('97.113.15.2')], netinfo_cell.sender_addresses)
    self.assertEqual(ZERO * 492, netinfo_cell.unused)

    self.assertEqual(b'', content)  # check that we've consumed all of the bytes
Beispiel #2
0
  def _unpack(cls, content, circ_id, link_protocol):
    timestamp, content = Size.LONG.pop(content)
    receiver_address, content = Address.pop(content)

    sender_addresses = []
    sender_addr_count, content = Size.CHAR.pop(content)

    for i in range(sender_addr_count):
      addr, content = Address.pop(content)
      sender_addresses.append(addr)

    return NetinfoCell(receiver_address, sender_addresses, datetime.datetime.utcfromtimestamp(timestamp), unused = content)
Beispiel #3
0
    def test_constructor(self):
        test_data = (
            ((4, b'\x7f\x00\x00\x01'),
             ExpectedAddress(AddrType.IPv4, 4, '127.0.0.1',
                             b'\x7f\x00\x00\x01')),
            ((4, b'aq\x0f\x02'),
             ExpectedAddress(AddrType.IPv4, 4, '97.113.15.2', b'aq\x0f\x02')),
            ((6, b' \x01\r\xb8\x00\x00\x00\x00\x00\x00\xff\x00\x00B\x83)'),
             ExpectedAddress(
                 AddrType.IPv6, 6, '2001:0db8:0000:0000:0000:ff00:0042:8329',
                 b' \x01\r\xb8\x00\x00\x00\x00\x00\x00\xff\x00\x00B\x83)')),
            ((AddrType.IPv4, '127.0.0.1'),
             ExpectedAddress(AddrType.IPv4, 4, '127.0.0.1',
                             b'\x7f\x00\x00\x01')),
            ((AddrType.IPv4, '97.113.15.2'),
             ExpectedAddress(AddrType.IPv4, 4, '97.113.15.2', b'aq\x0f\x02')),
            ((AddrType.IPv6, '2001:0db8:0000:0000:0000:ff00:0042:8329'),
             ExpectedAddress(
                 AddrType.IPv6, 6, '2001:0db8:0000:0000:0000:ff00:0042:8329',
                 b' \x01\r\xb8\x00\x00\x00\x00\x00\x00\xff\x00\x00B\x83)')),
            ((AddrType.IPv6, '2001:0DB8:AC10:FE01::'),
             ExpectedAddress(
                 AddrType.IPv6, 6, '2001:0db8:ac10:fe01:0000:0000:0000:0000',
                 b' \x01\r\xb8\xac\x10\xfe\x01\x00\x00\x00\x00\x00\x00\x00\x00'
             )),  # collaped and different case
        )

        for (addr_type, addr_value), expected in test_data:
            addr = Address(addr_value, addr_type)
            self.assertEqual(expected.type, addr.type)
            self.assertEqual(expected.type_int, addr.type_int)
            self.assertEqual(expected.value, addr.value)
            self.assertEqual(expected.value_bin, addr.value_bin)

        # when an IPv4 or IPv6 address the type is optional

        self.assertEqual(AddrType.IPv4, Address('127.0.0.1').type)
        self.assertEqual(AddrType.IPv6, Address('2001:0DB8:AC10:FE01::').type)

        self.assertRaisesRegexp(
            ValueError,
            re.escape(
                "Packed IPv4 addresses should be four bytes, but was: '\\x7f\\x00'"
            ), Address, '\x7f\x00', 4)
        self.assertRaisesRegexp(
            ValueError,
            re.escape(
                "Packed IPv6 addresses should be sixteen bytes, but was: '\\x7f\\x00'"
            ), Address, '\x7f\x00', 6)
        self.assertRaisesRegexp(
            ValueError, re.escape("'nope' isn't an IPv4 or IPv6 address"),
            Address, 'nope')
Beispiel #4
0
    def _unpack(
        cls, content: bytes, circ_id: int,
        link_protocol: 'stem.client.datatype.LinkProtocol'
    ) -> 'stem.client.cell.NetinfoCell':
        timestamp, content = Size.LONG.pop(content)
        receiver_address, content = Address.pop(content)

        sender_addresses = []
        sender_addr_count, content = Size.CHAR.pop(content)

        for i in range(sender_addr_count):
            addr, content = Address.pop(content)
            sender_addresses.append(addr)

        return NetinfoCell(receiver_address,
                           sender_addresses,
                           datetime.datetime.utcfromtimestamp(timestamp),
                           unused=content)
Beispiel #5
0
    def test_packing(self):
        test_data = {
            b'\x04\x04\x7f\x00\x00\x01':
            Address('127.0.0.1'),
            b'\x06\x10 \x01\r\xb8\x00\x00\x00\x00\x00\x00\xff\x00\x00B\x83)':
            Address('2001:0db8:0000:0000:0000:ff00:0042:8329'),
        }

        for cell_bytes, address in test_data.items():
            self.assertEqual(cell_bytes, address.pack())
            self.assertEqual(address, Address.unpack(cell_bytes))

        addr, content = Address.pop(
            b'\x04\x04\x7f\x00\x00\x01\x01\x04\x04aq\x0f\x02\x00\x00\x00\x00')
        self.assertEqual(b'\x01\x04\x04aq\x0f\x02\x00\x00\x00\x00', content)

        self.assertEqual(AddrType.IPv4, addr.type)
        self.assertEqual(4, addr.type_int)
        self.assertEqual('127.0.0.1', addr.value)
        self.assertEqual(b'\x7f\x00\x00\x01', addr.value_bin)
Beispiel #6
0
     b'\x92O\x0c\xcb\xa8\xac\xfb\xc9\x7f\xd0\rz\x1a\x03u\x91\xceas\xce',
     b'\x13Z\x99\xb2\x1e\xb6\x05\x85\x17\xfc\x1c\x00{\xa9\xae\x83^K\x99\x00',
     b'\x01' + ZERO * 468, 5),
}

VERSIONS_CELLS = {
    b'\x00\x00\x07\x00\x00': ([], 2),
    b'\x00\x00\x07\x00\x02\x00\x01': ([1], 2),
    b'\x00\x00\x07\x00\x06\x00\x01\x00\x02\x00\x03': ([1, 2, 3], 2),
    b'\x00\x00\x00\x00\x07\x00\x08\x00\x01\x00\x02\x00\x03\x00\x04':
    ([1, 2, 3, 4], 4),
}

NETINFO_CELLS = {
    b'\x00\x00\x08ZZ\xb6\x90\x04\x04\x7f\x00\x00\x01\x01\x04\x04aq\x0f\x02' + ZERO * (FIXED_PAYLOAD_LEN - 17):
    (datetime.datetime(2018, 1, 14, 1, 46, 56), Address('127.0.0.1'),
     [Address('97.113.15.2')], ZERO * 492, 2),
    b'\x00\x00\x08ZZ\xb6\x90\x04\x04\x7f\x00\x00\x01\x01\x04\x04aq\x0f\x02' + b'\x01' + ZERO * (FIXED_PAYLOAD_LEN - 18):
    (datetime.datetime(2018, 1, 14, 1, 46, 56), Address('127.0.0.1'),
     [Address('97.113.15.2')], b'\x01' + ZERO * 491, 2),
}

VPADDING_CELL_EMPTY_PACKED = b'\x00\x00\x80\x00\x00'

VPADDING_CELLS = {
    VPADDING_CELL_EMPTY_PACKED: (b'', 2),
    b'\x00\x00\x80\x00\x01\x08': (b'\x08', 2),
    b'\x00\x00\x80\x00\x02\x08\x11': (b'\x08\x11', 2),
    b'\x00\x00\x80\x01\xfd' + RANDOM_PAYLOAD: (RANDOM_PAYLOAD, 2),
}
Beispiel #7
0
  async def connect(address: str, port: int, link_protocols: Sequence['stem.client.datatype.LinkProtocol'] = DEFAULT_LINK_PROTOCOLS) -> 'stem.client.Relay':  # type: ignore
    """
    Establishes a connection with the given ORPort.

    :param address: ip address of the relay
    :param port: ORPort of the relay
    :param link_protocols: acceptable link protocol versions

    :raises:
      * **ValueError** if address or port are invalid
      * :class:`stem.SocketError` if we're unable to establish a connection
    """

    relay_addr = Address(address)

    if not stem.util.connection.is_valid_port(port):
      raise ValueError("'%s' isn't a valid port" % port)
    elif not link_protocols:
      raise ValueError("Connection can't be established without a link protocol.")

    try:
      conn = stem.socket.RelaySocket(address, port)
      await conn.connect()
    except stem.SocketError as exc:
      if 'Connect call failed' in str(exc):
        raise stem.SocketError("Failed to connect to %s:%i. Maybe it isn't an ORPort?" % (address, port))

      # If not an ORPort (for instance, mistakenly connecting to a ControlPort
      # instead) we'll likely fail during SSL negotiation. This can result
      # in a variety of responses so normalizing what we can...
      #
      #   Debian 9.5:     [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:661)
      #   Ubuntu 16.04:   [SSL: UNKNOWN_PROTOCOL] unknown protocol (_ssl.c:590)
      #   Ubuntu 12.04:   [Errno 1] _ssl.c:504: error:140770FC:SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol

      if 'unknown protocol' in str(exc) or 'wrong version number' in str(exc):
        raise stem.SocketError("Failed to SSL authenticate to %s:%i. Maybe it isn't an ORPort?" % (address, port))

      raise

    # To negotiate our link protocol the first VERSIONS cell is expected to use
    # a circuit ID field size from protocol version 1-3 for backward
    # compatibility...
    #
    #   The first VERSIONS cell, and any cells sent before the
    #   first VERSIONS cell, always have CIRCID_LEN == 2 for backward
    #   compatibility.

    await conn.send(stem.client.cell.VersionsCell(link_protocols).pack(2))  # type: ignore
    response = await conn.recv()

    # Link negotiation ends right away if we lack a common protocol
    # version. (#25139)

    if not response:
      await conn.close()
      raise stem.SocketError('Unable to establish a common link protocol with %s:%i' % (address, port))

    versions_reply = stem.client.cell.Cell.pop(response, 2)[0]  # type: stem.client.cell.VersionsCell # type: ignore
    common_protocols = set(link_protocols).intersection(versions_reply.versions)

    if not common_protocols:
      await conn.close()
      raise stem.SocketError('Unable to find a common link protocol. We support %s but %s:%i supports %s.' % (', '.join(map(str, link_protocols)), address, port, ', '.join(map(str, versions_reply.versions))))

    # Establishing connections requires sending a NETINFO, but including our
    # address is optional. We can revisit including it when we have a usecase
    # where it would help.

    link_protocol = max(common_protocols)
    await conn.send(stem.client.cell.NetinfoCell(relay_addr, []).pack(link_protocol))

    return Relay(conn, link_protocol)
Beispiel #8
0
  def connect(address, port, link_protocols = DEFAULT_LINK_PROTOCOLS):
    """
    Establishes a connection with the given ORPort.

    :param str address: ip address of the relay
    :param int port: ORPort of the relay
    :param tuple link_protocols: acceptable link protocol versions

    :raises:
      * **ValueError** if address or port are invalid
      * :class:`stem.SocketError` if we're unable to establish a connection
    """

    relay_addr = Address(address)

    if not stem.util.connection.is_valid_port(port):
      raise ValueError("'%s' isn't a valid port" % port)
    elif not link_protocols:
      raise ValueError("Connection can't be established without a link protocol.")

    try:
      conn = stem.socket.RelaySocket(address, port)
    except stem.SocketError as exc:
      if 'Connection refused' in str(exc):
        raise stem.SocketError("Failed to connect to %s:%i. Maybe it isn't an ORPort?" % (address, port))
      elif 'SSL: ' in str(exc):
        raise stem.SocketError("Failed to SSL authenticate to %s:%i. Maybe it isn't an ORPort?" % (address, port))
      else:
        raise

    # To negotiate our link protocol the first VERSIONS cell is expected to use
    # a circuit ID field size from protocol version 1-3 for backward
    # compatibility...
    #
    #   The first VERSIONS cell, and any cells sent before the
    #   first VERSIONS cell, always have CIRCID_LEN == 2 for backward
    #   compatibility.

    conn.send(stem.client.cell.VersionsCell(link_protocols).pack(2))
    response = conn.recv()

    # Link negotiation ends right away if we lack a common protocol
    # version. (#25139)

    if not response:
      conn.close()
      raise stem.SocketError('Unable to establish a common link protocol with %s:%i' % (address, port))

    versions_reply = stem.client.cell.Cell.pop(response, 2)[0]
    common_protocols = set(link_protocols).intersection(versions_reply.versions)

    if not common_protocols:
      conn.close()
      raise stem.SocketError('Unable to find a common link protocol. We support %s but %s:%i supports %s.' % (', '.join(link_protocols), address, port, ', '.join(versions_reply.versions)))

    # Establishing connections requires sending a NETINFO, but including our
    # address is optional. We can revisit including it when we have a usecase
    # where it would help.

    link_protocol = max(common_protocols)
    conn.send(stem.client.cell.NetinfoCell(relay_addr, []).pack(link_protocol))

    return Relay(conn, link_protocol)
Beispiel #9
0
 def test_unknown_type(self):
     addr = Address('hello', 12)
     self.assertEqual(AddrType.UNKNOWN, addr.type)
     self.assertEqual(12, addr.type_int)
     self.assertEqual(None, addr.value)
     self.assertEqual('hello', addr.value_bin)
Beispiel #10
0
CREATED_FAST_CELLS = {
  (b'\x80\x00\x00\x00\x06\x92O\x0c\xcb\xa8\xac\xfb\xc9\x7f\xd0\rz\x1a\x03u\x91\xceas\xce\x13Z\x99\xb2\x1e\xb6\x05\x85\x17\xfc\x1c\x00{\xa9\xae\x83^K\x99\xb2' + ZERO * 469): (2147483648, b'\x92O\x0c\xcb\xa8\xac\xfb\xc9\x7f\xd0\rz\x1a\x03u\x91\xceas\xce', b'\x13Z\x99\xb2\x1e\xb6\x05\x85\x17\xfc\x1c\x00{\xa9\xae\x83^K\x99\xb2', ZERO * 469, 5),
  (b'\x80\x00\x00\x00\x06\x92O\x0c\xcb\xa8\xac\xfb\xc9\x7f\xd0\rz\x1a\x03u\x91\xceas\xce\x13Z\x99\xb2\x1e\xb6\x05\x85\x17\xfc\x1c\x00{\xa9\xae\x83^K\x99\x00' + ZERO * 469): (2147483648, b'\x92O\x0c\xcb\xa8\xac\xfb\xc9\x7f\xd0\rz\x1a\x03u\x91\xceas\xce', b'\x13Z\x99\xb2\x1e\xb6\x05\x85\x17\xfc\x1c\x00{\xa9\xae\x83^K\x99\x00', ZERO * 469, 5),
  (b'\x80\x00\x00\x00\x06\x92O\x0c\xcb\xa8\xac\xfb\xc9\x7f\xd0\rz\x1a\x03u\x91\xceas\xce\x13Z\x99\xb2\x1e\xb6\x05\x85\x17\xfc\x1c\x00{\xa9\xae\x83^K\x99\x00' + b'\x01' + ZERO * 468): (2147483648, b'\x92O\x0c\xcb\xa8\xac\xfb\xc9\x7f\xd0\rz\x1a\x03u\x91\xceas\xce', b'\x13Z\x99\xb2\x1e\xb6\x05\x85\x17\xfc\x1c\x00{\xa9\xae\x83^K\x99\x00', b'\x01' + ZERO * 468, 5),
}

VERSIONS_CELLS = {
  b'\x00\x00\x07\x00\x00': ([], 2),
  b'\x00\x00\x07\x00\x02\x00\x01': ([1], 2),
  b'\x00\x00\x07\x00\x06\x00\x01\x00\x02\x00\x03': ([1, 2, 3], 2),
  b'\x00\x00\x00\x00\x07\x00\x08\x00\x01\x00\x02\x00\x03\x00\x04': ([1, 2, 3, 4], 4),
}

NETINFO_CELLS = {
  b'\x00\x00\x08ZZ\xb6\x90\x04\x04\x7f\x00\x00\x01\x01\x04\x04aq\x0f\x02' + ZERO * (FIXED_PAYLOAD_LEN - 17): (datetime.datetime(2018, 1, 14, 1, 46, 56), Address('127.0.0.1'), [Address('97.113.15.2')], ZERO * 492, 2),
  b'\x00\x00\x08ZZ\xb6\x90\x04\x04\x7f\x00\x00\x01\x01\x04\x04aq\x0f\x02' + b'\x01' + ZERO * (FIXED_PAYLOAD_LEN - 18): (datetime.datetime(2018, 1, 14, 1, 46, 56), Address('127.0.0.1'), [Address('97.113.15.2')], b'\x01' + ZERO * 491, 2),
}

VPADDING_CELL_EMPTY_PACKED = b'\x00\x00\x80\x00\x00'

VPADDING_CELLS = {
  VPADDING_CELL_EMPTY_PACKED: (b'', 2),
  b'\x00\x00\x80\x00\x01\x08': (b'\x08', 2),
  b'\x00\x00\x80\x00\x02\x08\x11': (b'\x08\x11', 2),
  b'\x00\x00\x80\x01\xfd' + RANDOM_PAYLOAD: (RANDOM_PAYLOAD, 2),
}

CERTS_CELLS = {
  b'\x00\x00\x81\x00\x01\x00': ([], b'', 2),
  b'\x00\x00\x81\x00\x04\x01\x01\x00\x00': ([Certificate(1, b'')], b'', 2),
Beispiel #11
0
     b'\x92O\x0c\xcb\xa8\xac\xfb\xc9\x7f\xd0\rz\x1a\x03u\x91\xceas\xce',
     b'\x13Z\x99\xb2\x1e\xb6\x05\x85\x17\xfc\x1c\x00{\xa9\xae\x83^K\x99\x00'),
}

VERSIONS_CELLS = {
    b'\x00\x00\x07\x00\x00': ([], 2),
    b'\x00\x00\x07\x00\x02\x00\x01': ([1], 2),
    b'\x00\x00\x07\x00\x06\x00\x01\x00\x02\x00\x03': ([1, 2, 3], 2),
    b'\x00\x00\x00\x00\x07\x00\x08\x00\x01\x00\x02\x00\x03\x00\x04':
    ([1, 2, 3, 4], 4),
}

NETINFO_CELLS = {
    b'\x00\x00\x08ZZ\xb6\x90\x04\x04\x7f\x00\x00\x01\x01\x04\x04aq\x0f\x02' + ZERO * (FIXED_PAYLOAD_LEN - 17):
    (datetime.datetime(2018, 1, 14, 1, 46,
                       56), Address('127.0.0.1'), [Address('97.113.15.2')]),
}

VPADDING_CELL_EMPTY_PACKED = b'\x00\x00\x80\x00\x00'

VPADDING_CELLS = {
    VPADDING_CELL_EMPTY_PACKED: b'',
    b'\x00\x00\x80\x00\x01\x08': b'\x08',
    b'\x00\x00\x80\x00\x02\x08\x11': b'\x08\x11',
    b'\x00\x00\x80\x01\xfd' + RANDOM_PAYLOAD: RANDOM_PAYLOAD,
}

CERTS_CELLS = {
    b'\x00\x00\x81\x00\x01\x00': [],
    b'\x00\x00\x81\x00\x04\x01\x01\x00\x00': [Certificate(1, b'')],
    b'\x00\x00\x81\x00\x05\x01\x01\x00\x01\x08': [Certificate(1, b'\x08')],