fall backs to SOCKS if we can't reach control port

This commit is contained in:
Brian Warner 2017-05-23 15:01:57 -07:00
parent 46a9c9eeb9
commit 269faf190a
2 changed files with 53 additions and 19 deletions

View File

@ -4,7 +4,7 @@ from twisted.trial import unittest
from twisted.internet import defer
from twisted.internet.error import ConnectError
from ..tor_manager import get_tor
from ..tor_manager import get_tor, SocksOnlyTor
from ..errors import NoTorError
from .._interfaces import ITorManager
@ -62,7 +62,7 @@ class Tor(unittest.TestCase):
tor = self.successResultOf(d)
self.assertIs(tor, my_tor)
self.assert_(ITorManager.providedBy(tor))
self.assertEqual(stderr.getvalue(), " using Tor\n")
self.assertEqual(stderr.getvalue(), " using Tor via control port\n")
def test_connect_fails(self):
reactor = object()
@ -74,7 +74,27 @@ class Tor(unittest.TestCase):
d = get_tor(reactor, tor_control_port=tcp, stderr=stderr)
self.assertNoResult(d)
self.assertEqual(connect.mock_calls, [mock.call(reactor, tcp)])
connect_d.errback(ConnectError())
self.failureResultOf(d, ConnectError)
tor = self.successResultOf(d)
self.assertIsInstance(tor, SocksOnlyTor)
self.assert_(ITorManager.providedBy(tor))
self.assertEqual(tor._reactor, reactor)
self.assertEqual(stderr.getvalue(),
" unable to find control port, bailing\n")
" unable to find Tor control port, using SOCKS\n")
class SocksOnly(unittest.TestCase):
def test_tor(self):
reactor = object()
sot = SocksOnlyTor(reactor)
fake_ep = object()
with mock.patch("wormhole.tor_manager.txtorcon.TorClientEndpoint",
return_value=fake_ep) as tce:
ep = sot.stream_via("host", "port")
self.assertIs(ep, fake_ep)
self.assertEqual(tce.mock_calls, [mock.call("host", "port",
socks_endpoint=None,
tls=False,
reactor=reactor)])

View File

@ -1,5 +1,6 @@
from __future__ import print_function, unicode_literals
import sys
from attr import attrs, attrib
from zope.interface.declarations import directlyProvides
from twisted.internet.defer import inlineCallbacks, returnValue
try:
@ -9,6 +10,18 @@ except ImportError:
from . import _interfaces, errors
from .timing import DebugTiming
@attrs
class SocksOnlyTor(object):
_reactor = attrib()
def stream_via(self, host, port, tls=False):
return txtorcon.TorClientEndpoint(
host, port,
socks_endpoint=None, # tries localhost:9050 and 9150
tls=tls,
reactor=self._reactor,
)
@inlineCallbacks
def get_tor(reactor, launch_tor=False, tor_control_port=None,
timing=None, stderr=sys.stderr):
@ -24,8 +37,9 @@ def get_tor(reactor, launch_tor=False, tor_control_port=None,
With no arguments, I will try to connect to an existing Tor's control
port at the usual places: [unix:/var/run/tor/control,
tcp:127.0.0.1:9051, tcp:127.0.0.1:9151]. If any are successful, I'll
ask that Tor for its SOCKS port. If none are successful, I'll attempt
to do SOCKS to tcp:127.0.0.1:9050.
ask that Tor for its SOCKS port. If none are successful, I'll
attempt to do SOCKS to the usual places: [tcp:127.0.0.1:9050,
tcp:127.0.0.1:9150].
If I am unable to make a SOCKS connection, the initial connection to
the Rendezvous Server will fail, and the program will terminate.
@ -69,17 +83,17 @@ def get_tor(reactor, launch_tor=False, tor_control_port=None,
else:
with timing.add("find tor"):
try:
# If tor_control_port is None (the default), txtorcon
# will look through a list of usual places. If it is set,
# it will look only in the place we tell it to.
tor = yield txtorcon.connect(reactor, tor_control_port)
print(" using Tor", file=stderr)
print(" using Tor via control port", file=stderr)
except Exception:
#socks_desc = "tcp:127.0.0.1:9050" # fallback
#print(" using Tor (SOCKS port %s)" % socks_desc,
# file=stderr)
print(" unable to find control port, bailing",
# TODO: make this more specific. I think connect() is
# likely to throw a reactor.connectTCP -type error, like
# ConnectionFailed or ConnectionRefused or something
print(" unable to find Tor control port, using SOCKS",
file=stderr)
# TODO: something nicer. I think connect() is likely to throw
# a reactor.connectTCP -type error, like ConnectionFailed or
# ConnectionRefused or something
raise
tor = SocksOnlyTor(reactor)
directlyProvides(tor, _interfaces.ITorManager)
returnValue(tor)