add --tor support

This commit is contained in:
Brian Warner 2016-01-29 13:40:41 -08:00
parent ed6e5ff169
commit 01ed9902de
6 changed files with 58 additions and 13 deletions

View File

@ -31,6 +31,8 @@ g.add_argument("--twisted", action="store_true",
help="use Twisted-based implementations, for testing") help="use Twisted-based implementations, for testing")
g.add_argument("--no-listen", action="store_true", g.add_argument("--no-listen", action="store_true",
help="(debug) don't open a listening socket for Transit") help="(debug) don't open a listening socket for Transit")
g.add_argument("--tor", action="store_true",
help="use Tor when connecting")
parser.set_defaults(timing=None) parser.set_defaults(timing=None)
subparsers = parser.add_subparsers(title="subcommands", subparsers = parser.add_subparsers(title="subcommands",
dest="subcommand") dest="subcommand")

View File

@ -39,14 +39,25 @@ class TwistedReceiver(BlockingReceiver):
# TODO: @handle_server_error # TODO: @handle_server_error
@inlineCallbacks @inlineCallbacks
def go(self): def go(self):
w = Wormhole(APPID, self.args.relay_url, timing=self.args.timing) tor_manager = None
if self.args.tor:
from ..twisted.tor_manager import TorManager
tor_manager = TorManager(reactor)
# For now, block everything until Tor has started. Soon: launch
# tor in parallel with everything else, make sure the TorManager
# can lazy-provide an endpoint, and overlap the startup process
# with the user handing off the wormhole code
yield tor_manager.start()
rc = yield self._go(w) w = Wormhole(APPID, self.args.relay_url, tor_manager,
timing=self.args.timing)
rc = yield self._go(w, tor_manager)
yield w.close() yield w.close()
returnValue(rc) returnValue(rc)
@inlineCallbacks @inlineCallbacks
def _go(self, w): def _go(self, w, tor_manager):
self.handle_code(w) self.handle_code(w)
verifier = yield w.get_verifier() verifier = yield w.get_verifier()
self.show_verifier(verifier) self.show_verifier(verifier)
@ -57,13 +68,13 @@ class TwistedReceiver(BlockingReceiver):
returnValue(0) returnValue(0)
if "file" in them_d: if "file" in them_d:
f = self.handle_file(them_d) f = self.handle_file(them_d)
rp = yield self.establish_transit(w, them_d) rp = yield self.establish_transit(w, them_d, tor_manager)
yield self.transfer_data(rp, f) yield self.transfer_data(rp, f)
self.write_file(f) self.write_file(f)
yield self.close_transit(rp) yield self.close_transit(rp)
elif "directory" in them_d: elif "directory" in them_d:
f = self.handle_directory(them_d) f = self.handle_directory(them_d)
rp = yield self.establish_transit(w, them_d) rp = yield self.establish_transit(w, them_d, tor_manager)
yield self.transfer_data(rp, f) yield self.transfer_data(rp, f)
self.write_directory(f) self.write_directory(f)
yield self.close_transit(rp) yield self.close_transit(rp)
@ -96,10 +107,11 @@ class TwistedReceiver(BlockingReceiver):
yield w.send_data(data) yield w.send_data(data)
@inlineCallbacks @inlineCallbacks
def establish_transit(self, w, them_d): def establish_transit(self, w, them_d, tor_manager):
transit_key = w.derive_key(APPID+u"/transit-key") transit_key = w.derive_key(APPID+u"/transit-key")
transit_receiver = TransitReceiver(self.args.transit_helper, transit_receiver = TransitReceiver(self.args.transit_helper,
no_listen=self.args.no_listen, no_listen=self.args.no_listen,
tor_manager=tor_manager,
timing=self.args.timing) timing=self.args.timing)
transit_receiver.set_transit_key(transit_key) transit_receiver.set_transit_key(transit_key)
direct_hints = yield transit_receiver.get_direct_hints() direct_hints = yield transit_receiver.get_direct_hints()

View File

@ -42,11 +42,22 @@ def send_twisted(args):
print(u"On the other computer, please run: %s" % other_cmd, print(u"On the other computer, please run: %s" % other_cmd,
file=args.stdout) file=args.stdout)
w = Wormhole(APPID, args.relay_url, timing=args.timing) tor_manager = None
if args.tor:
from ..twisted.tor_manager import TorManager
tor_manager = TorManager(reactor)
# For now, block everything until Tor has started. Soon: launch tor
# in parallel with everything else, make sure the TorManager can
# lazy-provide an endpoint, and overlap the startup process with the
# user handing off the wormhole code
yield tor_manager.start()
w = Wormhole(APPID, args.relay_url, tor_manager, timing=args.timing)
if fd_to_send: if fd_to_send:
transit_sender = TransitSender(args.transit_helper, transit_sender = TransitSender(args.transit_helper,
no_listen=args.no_listen, no_listen=args.no_listen,
tor_manager=tor_manager,
timing=args.timing) timing=args.timing)
phase1["transit"] = transit_data = {} phase1["transit"] = transit_data = {}
transit_data["relay_connection_hints"] = transit_sender.get_relay_hints() transit_data["relay_connection_hints"] = transit_sender.get_relay_hints()

View File

@ -21,6 +21,8 @@ def dispatch(args):
from ..servers import cmd_usage from ..servers import cmd_usage
return cmd_usage.tail_usage(args) return cmd_usage.tail_usage(args)
if args.tor:
args.twisted = True
if args.func == "send/send": if args.func == "send/send":
if args.twisted: if args.twisted:
from . import cmd_send_twisted from . import cmd_send_twisted

View File

@ -181,15 +181,23 @@ class Channel:
return d return d
class ChannelManager: class ChannelManager:
def __init__(self, relay, appid, side, handle_welcome, timing=None): def __init__(self, relay, appid, side, handle_welcome, tor_manager=None,
timing=None):
assert isinstance(relay, type(u"")) assert isinstance(relay, type(u""))
self._relay = relay self._relay = relay
self._appid = appid self._appid = appid
self._side = side self._side = side
self._handle_welcome = handle_welcome self._handle_welcome = handle_welcome
self._timing = timing or DebugTiming()
self._pool = web_client.HTTPConnectionPool(reactor, True) # persistent self._pool = web_client.HTTPConnectionPool(reactor, True) # persistent
self._agent = web_client.Agent(reactor, pool=self._pool) if tor_manager:
print("ChannelManager using tor")
epf = tor_manager.get_web_agent_endpoint_factory()
agent = web_client.Agent.usingEndpointFactory(reactor, epf,
pool=self._pool)
else:
agent = web_client.Agent(reactor, pool=self._pool)
self._agent = agent
self._timing = timing or DebugTiming()
@inlineCallbacks @inlineCallbacks
def allocate(self): def allocate(self):
@ -250,13 +258,14 @@ class Wormhole:
version_warning_displayed = False version_warning_displayed = False
_send_confirm = True _send_confirm = True
def __init__(self, appid, relay_url, timing=None): def __init__(self, appid, relay_url, tor_manager=None, timing=None):
if not isinstance(appid, type(u"")): raise TypeError(type(appid)) if not isinstance(appid, type(u"")): raise TypeError(type(appid))
if not isinstance(relay_url, type(u"")): if not isinstance(relay_url, type(u"")):
raise TypeError(type(relay_url)) raise TypeError(type(relay_url))
if not relay_url.endswith(u"/"): raise UsageError if not relay_url.endswith(u"/"): raise UsageError
self._appid = appid self._appid = appid
self._relay_url = relay_url self._relay_url = relay_url
self._tor_manager = tor_manager
self._timing = timing or DebugTiming() self._timing = timing or DebugTiming()
self._set_side(hexlify(os.urandom(5)).decode("ascii")) self._set_side(hexlify(os.urandom(5)).decode("ascii"))
self.code = None self.code = None
@ -272,6 +281,7 @@ class Wormhole:
self._side = side self._side = side
self._channel_manager = ChannelManager(self._relay_url, self._appid, self._channel_manager = ChannelManager(self._relay_url, self._appid,
self._side, self.handle_welcome, self._side, self.handle_welcome,
self._tor_manager,
self._timing) self._timing)
self._channel = None self._channel = None

View File

@ -469,7 +469,7 @@ def there_can_be_only_one(contenders):
class Common: class Common:
RELAY_DELAY = 2.0 RELAY_DELAY = 2.0
def __init__(self, transit_relay, no_listen=False, def __init__(self, transit_relay, no_listen=False, tor_manager=None,
reactor=reactor, timing=None): reactor=reactor, timing=None):
if transit_relay: if transit_relay:
if not isinstance(transit_relay, type(u"")): if not isinstance(transit_relay, type(u"")):
@ -477,6 +477,7 @@ class Common:
self._transit_relays = [transit_relay] self._transit_relays = [transit_relay]
else: else:
self._transit_relays = [] self._transit_relays = []
self._tor_manager = tor_manager
self._transit_key = None self._transit_key = None
self._no_listen = no_listen self._no_listen = no_listen
self._waiting_for_transit_key = [] self._waiting_for_transit_key = []
@ -487,7 +488,7 @@ class Common:
self._timing_started = self._timing.add_event("transit") self._timing_started = self._timing.add_event("transit")
def _build_listener(self): def _build_listener(self):
if self._no_listen: if self._no_listen or self._tor_manager:
return ([], None) return ([], None)
portnum = allocate_tcp_port() portnum = allocate_tcp_port()
direct_hints = [u"tcp:%s:%d" % (addr, portnum) direct_hints = [u"tcp:%s:%d" % (addr, portnum)
@ -686,10 +687,17 @@ class Common:
# TODO: use transit_common.parse_hint_tcp # TODO: use transit_common.parse_hint_tcp
if ":" not in hint: if ":" not in hint:
return None return None
pieces = hint.split(":")
hint_type = hint.split(":")[0] hint_type = hint.split(":")[0]
if hint_type == "tor" and self._tor_manager:
return self._tor_manager.get_endpoint_for(pieces[1], int(pieces[2]))
if hint_type != "tcp": if hint_type != "tcp":
return None return None
pieces = hint.split(":") pieces = hint.split(":")
if self._tor_manager:
# our TorManager will return None for non-public IPv4 addresses
# and any IPv6 address
return self._tor_manager.get_endpoint_for(pieces[1], int(pieces[2]))
return endpoints.HostnameEndpoint(self._reactor, pieces[1], return endpoints.HostnameEndpoint(self._reactor, pieces[1],
int(pieces[2])) int(pieces[2]))