[tor-commits] [stem/master] Initial ORPort integ tests

atagar at torproject.org atagar at torproject.org
Wed Feb 7 19:44:51 UTC 2018


commit 3fe2221ae2bad6d826c05fd0ce96e5c09a21fc01
Author: Damian Johnson <atagar at torproject.org>
Date:   Sat Feb 3 14:13:27 2018 -0800

    Initial ORPort integ tests
    
    Nothing too interesting yet.
---
 stem/relay.py                    | 54 +++++++++++++++++++++++++++++-----------
 test/integ/__init__.py           |  1 +
 test/integ/client/__init__.py    |  7 ++++++
 test/integ/client/connection.py  | 49 ++++++++++++++++++++++++++++++++++++
 test/integ/control/controller.py |  4 +--
 test/runner.py                   |  4 ++-
 test/settings.cfg                |  1 +
 7 files changed, 103 insertions(+), 17 deletions(-)

diff --git a/stem/relay.py b/stem/relay.py
index 7d1e8282..20341721 100644
--- a/stem/relay.py
+++ b/stem/relay.py
@@ -15,30 +15,34 @@ a wrapper for :class:`~stem.socket.RelaySocket`, much the same way as
     | +- connect - Establishes a connection with a relay.
 """
 
+import stem
 import stem.client
 import stem.client.cell
 import stem.socket
 import stem.util.connection
 
-DEFAULT_LINK_VERSIONS = (3, 4, 5)
+DEFAULT_LINK_PROTOCOLS = (3, 4, 5)
 
 
 class Relay(object):
   """
   Connection with a Tor relay's ORPort.
+
+  :var int link_protocol: link protocol version we established
   """
 
-  def __init__(self, orport):
+  def __init__(self, orport, link_protocol):
+    self.link_protocol = link_protocol
     self._orport = orport
 
   @staticmethod
-  def connect(address, port, link_versions = DEFAULT_LINK_VERSIONS):
+  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_versions: acceptable link protocol versions
+    :param tuple link_protocols: acceptable link protocol versions
 
     :raises:
       * **ValueError** if address or port are invalid
@@ -52,20 +56,42 @@ class Relay(object):
     else:
       raise ValueError("'%s' isn't an IPv4 or IPv6 address" % address)
 
-    if not stem.util.connection.is_port(port):
+    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: UNKNOWN_PROTOCOL' in str(exc):
+        raise stem.SocketError("Failed to SSL authenticate to %s:%i. Maybe it isn't an ORPort?" % (address, port))
+      else:
+        raise
+
+    conn.send(stem.client.cell.VersionsCell(link_protocols).pack())
+    response = conn.recv()
+
+    # Link negotiation ends right away if we lack a common protocol
+    # version. (#25139)
 
-    conn = stem.socket.RelaySocket(address, port)
-    conn.send(stem.client.cell.VersionsCell(link_versions).pack())
-    versions_reply = stem.client.cell.Cell.pop(conn.recv(), 2)[0]
+    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)))
 
-    # TODO: determine the highest common link versions
     # TODO: we should fill in our address, right?
     # TODO: what happens if we skip the NETINFO?
 
-    link_version = 3
-    conn.send(stem.client.cell.NetinfoCell(stem.client.Address(address, addr_type), []).pack(link_version))
-
-    # TODO: what if no link protocol versions are acceptable?
+    link_protocol = max(common_protocols)
+    conn.send(stem.client.cell.NetinfoCell(stem.client.Address(address, addr_type), []).pack(link_protocol))
 
-    return Relay(conn)
+    return Relay(conn, link_protocol)
diff --git a/test/integ/__init__.py b/test/integ/__init__.py
index 886d1c89..31e6084f 100644
--- a/test/integ/__init__.py
+++ b/test/integ/__init__.py
@@ -3,6 +3,7 @@ Integration tests for the stem library.
 """
 
 __all__ = [
+  'client',
   'connection',
   'control',
   'descriptor',
diff --git a/test/integ/client/__init__.py b/test/integ/client/__init__.py
new file mode 100644
index 00000000..8d77a653
--- /dev/null
+++ b/test/integ/client/__init__.py
@@ -0,0 +1,7 @@
+"""
+Integration tests for tor's ORPort (stem.relay and stem.client).
+"""
+
+__all__ = [
+  'connection',
+]
diff --git a/test/integ/client/connection.py b/test/integ/client/connection.py
new file mode 100644
index 00000000..bb6ae762
--- /dev/null
+++ b/test/integ/client/connection.py
@@ -0,0 +1,49 @@
+"""
+Integration tests for establishing a connection with tor's ORPort.
+"""
+
+import unittest
+
+import stem
+import test.runner
+
+from stem.relay import Relay
+
+
+class TestConnection(unittest.TestCase):
+  def test_invalid_arguments(self):
+    """
+    Provide invalid arguments to Relay.connect().
+    """
+
+    self.assertRaisesRegexp(ValueError, "'nope' isn't an IPv4 or IPv6 address", Relay.connect, 'nope', 80)
+    self.assertRaisesRegexp(ValueError, "'-54' isn't a valid port", Relay.connect, '127.0.0.1', -54)
+    self.assertRaisesRegexp(ValueError, "Connection can't be established without a link protocol.", Relay.connect, '127.0.0.1', 54, [])
+
+  def test_not_orport(self):
+    """
+    Attempt to connect to an ORPort that doesn't exist.
+    """
+
+    self.assertRaisesRegexp(stem.SocketError, "Failed to connect to 127.0.0.1:1587. Maybe it isn't an ORPort?", Relay.connect, '127.0.0.1', 1587)
+
+    # connect to our ControlPort like it's an ORPort
+
+    if test.runner.Torrc.PORT in test.runner.get_runner().get_options():
+      self.assertRaisesRegexp(stem.SocketError, "Failed to SSL authenticate to 127.0.0.1:1111. Maybe it isn't an ORPort?", Relay.connect, '127.0.0.1', test.runner.CONTROL_PORT)
+
+  def test_no_common_link_protocol(self):
+    """
+    Connection without a commonly accepted link protocol version.
+    """
+
+    for link_protocol in (1, 2, 6, 20):
+      self.assertRaisesRegexp(stem.SocketError, 'Unable to establish a common link protocol with 127.0.0.1:1113', Relay.connect, '127.0.0.1', test.runner.ORPORT, [link_protocol])
+
+  def test_established(self):
+    """
+    Successfully establish ORPort connection.
+    """
+
+    conn = Relay.connect('127.0.0.1', test.runner.ORPORT)
+    self.assertEqual(5, conn.link_protocol)
diff --git a/test/integ/control/controller.py b/test/integ/control/controller.py
index b2ba77a5..16061eee 100644
--- a/test/integ/control/controller.py
+++ b/test/integ/control/controller.py
@@ -845,7 +845,7 @@ class TestController(unittest.TestCase):
     runner = test.runner.get_runner()
 
     with runner.get_tor_controller() as controller:
-      self.assertEqual([], controller.get_ports(Listener.OR))
+      self.assertEqual([test.runner.ORPORT], controller.get_ports(Listener.OR))
       self.assertEqual([], controller.get_ports(Listener.DIR))
       self.assertEqual([test.runner.SOCKS_PORT], controller.get_ports(Listener.SOCKS))
       self.assertEqual([], controller.get_ports(Listener.TRANS))
@@ -866,7 +866,7 @@ class TestController(unittest.TestCase):
     runner = test.runner.get_runner()
 
     with runner.get_tor_controller() as controller:
-      self.assertEqual([], controller.get_listeners(Listener.OR))
+      self.assertEqual([('0.0.0.0', test.runner.ORPORT)], controller.get_listeners(Listener.OR))
       self.assertEqual([], controller.get_listeners(Listener.DIR))
       self.assertEqual([('127.0.0.1', test.runner.SOCKS_PORT)], controller.get_listeners(Listener.SOCKS))
       self.assertEqual([], controller.get_listeners(Listener.TRANS))
diff --git a/test/runner.py b/test/runner.py
index 0a307c87..fe01f74f 100644
--- a/test/runner.py
+++ b/test/runner.py
@@ -58,14 +58,16 @@ CONFIG = stem.util.conf.config_dict('test', {
 })
 
 SOCKS_PORT = 1112
+ORPORT = 1113
 
 BASE_TORRC = """# configuration for stem integration tests
 DataDirectory %%s
 SocksPort %i
+ORPort %i
 DownloadExtraInfo 1
 Log notice stdout
 Log notice file %%s/tor_log
-""" % SOCKS_PORT
+""" % (SOCKS_PORT, ORPORT)
 
 # singleton Runner instance
 INTEG_RUNNER = None
diff --git a/test/settings.cfg b/test/settings.cfg
index 4080ca2a..6d543bac 100644
--- a/test/settings.cfg
+++ b/test/settings.cfg
@@ -252,6 +252,7 @@ test.integ_tests
 |test.integ.interpreter.TestInterpreter
 |test.integ.version.TestVersion
 |test.integ.manual.TestManual
+|test.integ.client.connection.TestConnection
 |test.integ.response.protocolinfo.TestProtocolInfo
 |test.integ.socket.control_socket.TestControlSocket
 |test.integ.socket.control_message.TestControlMessage





More information about the tor-commits mailing list