1# -*- coding: utf-8 -*-
2
3from __future__ import absolute_import
4from __future__ import print_function
5from __future__ import with_statement
6
7import os
8import sys
9import six
10import shlex
11import tempfile
12import functools
13from io import StringIO
14from os.path import dirname, exists
15try:
16    from collections.abc import Sequence
17except ImportError:
18    from collections import Sequence
19
20from twisted.python import log
21from twisted.python.failure import Failure
22from twisted.internet.defer import inlineCallbacks, returnValue, Deferred, succeed, fail
23from twisted.internet import protocol, error
24from twisted.internet.endpoints import TCP4ClientEndpoint
25from twisted.internet.endpoints import UNIXClientEndpoint
26from twisted.internet.interfaces import IReactorTime, IReactorCore
27from twisted.internet.interfaces import IStreamClientEndpoint
28
29from zope.interface import implementer
30
31from txtorcon.util import delete_file_or_tree, find_keywords
32from txtorcon.util import find_tor_binary, available_tcp_port
33from txtorcon.log import txtorlog
34from txtorcon.torcontrolprotocol import TorProtocolFactory
35from txtorcon.torstate import TorState
36from txtorcon.torconfig import TorConfig
37from txtorcon.endpoints import TorClientEndpoint, _create_socks_endpoint
38from txtorcon.endpoints import TCPHiddenServiceEndpoint
39from txtorcon.onion import EphemeralOnionService, FilesystemOnionService, _validate_ports
40from txtorcon.util import _is_non_public_numeric_address
41
42from . import socks
43from .interface import ITor
44
45try:
46    from .controller_py3 import _AsyncOnionAuthContext
47    HAVE_ASYNC = True
48except Exception:
49    HAVE_ASYNC = False
50
51if sys.platform in ('linux', 'linux2', 'darwin'):
52    import pwd
53
54
55@inlineCallbacks
56def launch(reactor,
57           progress_updates=None,
58           control_port=None,
59           data_directory=None,
60           socks_port=None,
61           non_anonymous_mode=None,
62           stdout=None,
63           stderr=None,
64           timeout=None,
65           tor_binary=None,
66           user=None,  # XXX like the config['User'] special-casing from before
67           # 'users' probably never need these:
68           connection_creator=None,
69           kill_on_stderr=True,
70           _tor_config=None,  # a TorConfig instance, mostly for tests
71           ):
72    """
73    launches a new Tor process, and returns a Deferred that fires with
74    a new :class:`txtorcon.Tor` instance. From this instance, you can
75    create or get any "interesting" instances you need: the
76    :class:`txtorcon.TorConfig` instance, create endpoints, create
77    :class:`txtorcon.TorState` instance(s), etc.
78
79    Note that there is NO way to pass in a config; we only expost a
80    couple of basic Tor options. If you need anything beyond these,
81    you can access the ``TorConfig`` instance (via ``.config``)
82    and make any changes there, reflecting them in tor with
83    ``.config.save()``.
84
85    You can igore all the options and safe defaults will be
86    provided. However, **it is recommended to pass data_directory**
87    especially if you will be starting up Tor frequently, as it saves
88    a bunch of time (and bandwidth for the directory
89    authorities). "Safe defaults" means:
90
91      - a tempdir for a ``DataDirectory`` is used (respecting ``TMP``)
92        and is deleted when this tor is shut down (you therefore
93        *probably* want to supply the ``data_directory=`` kwarg);
94      - a random, currently-unused local TCP port is used as the
95        ``SocksPort`` (specify ``socks_port=`` if you want your
96        own). If you want no SOCKS listener at all, pass
97        ``socks_port=0``
98      - we set ``__OwningControllerProcess`` and call
99        ``TAKEOWNERSHIP`` so that if our control connection goes away,
100        tor shuts down (see `control-spec
101        <https://gitweb.torproject.org/torspec.git/blob/HEAD:/control-spec.txt>`_
102        3.23).
103      - the launched Tor will use ``COOKIE`` authentication.
104
105    :param reactor: a Twisted IReactorCore implementation (usually
106        twisted.internet.reactor)
107
108    :param progress_updates: a callback which gets progress updates; gets 3
109         args: percent, tag, summary (FIXME make an interface for this).
110
111    :param data_directory: set as the ``DataDirectory`` option to Tor,
112        this is where tor keeps its state information (cached relays,
113        etc); starting with an already-populated state directory is a lot
114        faster. If ``None`` (the default), we create a tempdir for this
115        **and delete it on exit**. It is recommended you pass something here.
116
117    :param non_anonymous_mode: sets the Tor options
118        `HiddenServiceSingleHopMode` and
119        `HiddenServiceNonAnonymousMode` to 1 and un-sets any
120        `SOCKSPort` config, thus putting this Tor client into
121        "non-anonymous mode" which allows starting so-called Single
122        Onion services -- which use single-hop circuits to rendezvous
123        points. See WARNINGs in Tor manual! Also you need Tor
124        `0.3.4.1` or later (e.g. any `0.3.5.*` or newer) for this to
125        work properly.
126
127    :param stdout: a file-like object to which we write anything that
128        Tor prints on stdout (just needs to support write()).
129
130    :param stderr: a file-like object to which we write anything that
131        Tor prints on stderr (just needs .write()). Note that we kill
132        Tor off by default if anything appears on stderr; pass
133        "kill_on_stderr=False" if you don't want this behavior.
134
135    :param tor_binary: path to the Tor binary to run. If None (the
136        default), we try to find the tor binary.
137
138    :param kill_on_stderr:
139        When True (the default), if Tor prints anything on stderr we
140        kill off the process, close the TorControlProtocol and raise
141        an exception.
142
143    :param connection_creator: is mostly available to ease testing, so
144        you probably don't want to supply this. If supplied, it is a
145        callable that should return a Deferred that delivers an
146        :api:`twisted.internet.interfaces.IProtocol <IProtocol>` or
147        ConnectError.
148        See :api:`twisted.internet.interfaces.IStreamClientEndpoint`.connect
149        Note that this parameter is ignored if config.ControlPort == 0
150
151    :return: a Deferred which callbacks with :class:`txtorcon.Tor`
152        instance, from which you can retrieve the TorControlProtocol
153        instance via the ``.protocol`` property.
154
155    HACKS:
156
157     1. It's hard to know when Tor has both (completely!) written its
158        authentication cookie file AND is listening on the control
159        port. It seems that waiting for the first 'bootstrap' message on
160        stdout is sufficient. Seems fragile...and doesn't work 100% of
161        the time, so FIXME look at Tor source.
162
163
164
165    XXX this "User" thing was, IIRC, a feature for root-using scripts
166    (!!) that were going to launch tor, but where tor would drop to a
167    different user. Do we still want to support this? Probably
168    relevant to Docker (where everything is root! yay!)
169
170    ``User``: if this exists, we attempt to set ownership of the tempdir
171    to this user (but only if our effective UID is 0).
172    """
173
174    # We have a slight problem with the approach: we need to pass a
175    # few minimum values to a torrc file so that Tor will start up
176    # enough that we may connect to it. Ideally, we'd be able to
177    # start a Tor up which doesn't really do anything except provide
178    # "AUTHENTICATE" and "GETINFO config/names" so we can do our
179    # config validation.
180
181    if not IReactorCore.providedBy(reactor):
182        raise ValueError(
183            "'reactor' argument must provide IReactorCore"
184            " (got '{}': {})".format(
185                type(reactor).__class__.__name__,
186                repr(reactor)
187            )
188        )
189
190    if tor_binary is None:
191        tor_binary = find_tor_binary()
192    if tor_binary is None:
193        # We fail right here instead of waiting for the reactor to start
194        raise TorNotFound('Tor binary could not be found')
195
196    # make sure we got things that have write() for stderr, stdout
197    # kwargs (XXX is there a "better" way to check for file-like
198    # object? do we use anything besides 'write()'?)
199    for arg in [stderr, stdout]:
200        if arg and not getattr(arg, "write", None):
201            raise RuntimeError(
202                'File-like object needed for stdout or stderr args.'
203            )
204
205    config = _tor_config or TorConfig()
206    if data_directory is not None:
207        user_set_data_directory = True
208        config.DataDirectory = data_directory
209        try:
210            os.mkdir(data_directory, 0o0700)
211        except OSError:
212            pass
213    else:
214        user_set_data_directory = False
215        data_directory = tempfile.mkdtemp(prefix='tortmp')
216        config.DataDirectory = data_directory
217        # note: we also set up the ProcessProtocol to delete this when
218        # Tor exits, this is "just in case" fallback:
219        reactor.addSystemEventTrigger(
220            'before', 'shutdown',
221            functools.partial(delete_file_or_tree, data_directory)
222        )
223
224    # things that used launch_tor() had to set ControlPort and/or
225    # SocksPort on the config to pass them, so we honour that here.
226    if control_port is None and _tor_config is not None:
227        try:
228            control_port = config.ControlPort
229        except KeyError:
230            control_port = None
231
232    if socks_port is None and _tor_config is not None:
233        try:
234            socks_port = config.SocksPort
235        except KeyError:
236            socks_port = None
237
238    if non_anonymous_mode:
239        if socks_port is not None:
240            raise ValueError(
241                "Cannot use SOCKS options with non_anonymous_mode=True"
242            )
243        config.HiddenServiceNonAnonymousMode = 1
244        config.HiddenServiceSingleHopMode = 1
245        config.SOCKSPort = 0
246    else:
247        if socks_port is None:
248            socks_port = yield available_tcp_port(reactor)
249        config.SOCKSPort = socks_port
250
251    try:
252        our_user = user or config.User
253    except KeyError:
254        pass
255    else:
256        # if we're root, make sure the directory is owned by the User
257        # that Tor is configured to drop to
258        if sys.platform in ('linux', 'linux2', 'darwin') and os.geteuid() == 0:
259            os.chown(data_directory, pwd.getpwnam(our_user).pw_uid, -1)
260
261    # user can pass in a control port, or we set one up here
262    if control_port is None:
263        # on posix-y systems, we can use a unix-socket
264        if sys.platform in ('linux', 'linux2', 'darwin'):
265            # note: tor will not accept a relative path for ControlPort
266            control_port = 'unix:{}'.format(
267                os.path.join(os.path.realpath(data_directory), 'control.socket')
268            )
269        else:
270            control_port = yield available_tcp_port(reactor)
271    else:
272        if str(control_port).startswith('unix:'):
273            control_path = control_port.lstrip('unix:')
274            containing_dir = dirname(control_path)
275            if not exists(containing_dir):
276                raise ValueError(
277                    "The directory containing '{}' must exist".format(
278                        containing_dir
279                    )
280                )
281            # Tor will be sad if the directory isn't 0700
282            mode = (0o0777 & os.stat(containing_dir).st_mode)
283            if mode & ~(0o0700):
284                raise ValueError(
285                    "The directory containing a unix control-socket ('{}') "
286                    "must only be readable by the user".format(containing_dir)
287                )
288    config.ControlPort = control_port
289
290    config.CookieAuthentication = 1
291    config.__OwningControllerProcess = os.getpid()
292    if connection_creator is None:
293        if str(control_port).startswith('unix:'):
294            connection_creator = functools.partial(
295                UNIXClientEndpoint(reactor, control_port[5:]).connect,
296                TorProtocolFactory()
297            )
298        else:
299            connection_creator = functools.partial(
300                TCP4ClientEndpoint(reactor, 'localhost', control_port).connect,
301                TorProtocolFactory()
302            )
303    # not an "else" on purpose; if we passed in "control_port=0" *and*
304    # a custom connection creator, we should still set this to None so
305    # it's never called (since we can't connect with ControlPort=0)
306    if control_port == 0:
307        connection_creator = None
308
309    # NOTE well, that if we don't pass "-f" then Tor will merrily load
310    # its default torrc, and apply our options over top... :/ should
311    # file a bug probably? --no-defaults or something maybe? (does
312    # --defaults-torrc - or something work?)
313    config_args = ['-f', '/dev/null/non-existant-on-purpose', '--ignore-missing-torrc']
314
315    # ...now add all our config options on the command-line. This
316    # avoids writing a temporary torrc.
317    for (k, v) in config.config_args():
318        config_args.append(k)
319        config_args.append(v)
320
321    process_protocol = TorProcessProtocol(
322        connection_creator,
323        progress_updates,
324        config, reactor,
325        timeout,
326        kill_on_stderr,
327        stdout,
328        stderr,
329    )
330    if control_port == 0:
331        connected_cb = succeed(None)
332    else:
333        connected_cb = process_protocol.when_connected()
334
335    # we set both to_delete and the shutdown events because this
336    # process might be shut down way before the reactor, but if the
337    # reactor bombs out without the subprocess getting closed cleanly,
338    # we'll want the system shutdown events triggered so the temporary
339    # files get cleaned up either way
340
341    # we don't want to delete the user's directories, just temporary
342    # ones this method created.
343    if not user_set_data_directory:
344        process_protocol.to_delete = [data_directory]
345        reactor.addSystemEventTrigger(
346            'before', 'shutdown',
347            functools.partial(delete_file_or_tree, data_directory)
348        )
349
350    log.msg('Spawning tor process with DataDirectory', data_directory)
351    args = [tor_binary] + config_args
352    transport = reactor.spawnProcess(
353        process_protocol,
354        tor_binary,
355        args=args,
356        env={'HOME': data_directory},
357        path=data_directory if os.path.exists(data_directory) else None,  # XXX error if it doesn't exist?
358    )
359    transport.closeStdin()
360    proto = yield connected_cb
361    # note "proto" here is a TorProcessProtocol
362
363    # we might need to attach this protocol to the TorConfig
364    if config.protocol is None and proto is not None and proto.tor_protocol is not None:
365        # proto is None in the ControlPort=0 case
366        yield config.attach_protocol(proto.tor_protocol)
367        # note that attach_protocol waits for the protocol to be
368        # boostrapped if necessary
369
370    returnValue(
371        Tor(
372            reactor,
373            config.protocol,
374            _tor_config=config,
375            _process_proto=process_protocol,
376            _non_anonymous=True if non_anonymous_mode else False,
377        )
378    )
379
380
381@inlineCallbacks
382def connect(reactor, control_endpoint=None, password_function=None):
383    """
384    Creates a :class:`txtorcon.Tor` instance by connecting to an
385    already-running tor's control port. For example, a common default
386    tor uses is UNIXClientEndpoint(reactor, '/var/run/tor/control') or
387    TCP4ClientEndpoint(reactor, 'localhost', 9051)
388
389    If only password authentication is available in the tor we connect
390    to, the ``password_function`` is called (if supplied) to retrieve
391    a valid password. This function can return a Deferred.
392
393    For example::
394
395        import txtorcon
396        from twisted.internet.task import react
397        from twisted.internet.defer import inlineCallbacks
398
399        @inlineCallbacks
400        def main(reactor):
401            tor = yield txtorcon.connect(
402                TCP4ClientEndpoint(reactor, "localhost", 9051)
403            )
404            state = yield tor.create_state()
405            for circuit in state.circuits:
406                print(circuit)
407
408    :param control_endpoint: None, an IStreamClientEndpoint to connect
409        to, or a Sequence of IStreamClientEndpoint instances to connect
410        to. If None, a list of defaults are tried.
411
412    :param password_function:
413        See :class:`txtorcon.TorControlProtocol`
414
415    :return:
416        a Deferred that fires with a :class:`txtorcon.Tor` instance
417    """
418
419    @inlineCallbacks
420    def try_endpoint(control_ep):
421        assert IStreamClientEndpoint.providedBy(control_ep)
422        proto = yield control_ep.connect(
423            TorProtocolFactory(
424                password_function=password_function
425            )
426        )
427        config = yield TorConfig.from_protocol(proto)
428        tor = Tor(reactor, proto, _tor_config=config)
429        returnValue(tor)
430
431    if control_endpoint is None:
432        to_try = [
433            UNIXClientEndpoint(reactor, '/var/run/tor/control'),
434            TCP4ClientEndpoint(reactor, '127.0.0.1', 9051),
435            TCP4ClientEndpoint(reactor, '127.0.0.1', 9151),
436        ]
437    elif IStreamClientEndpoint.providedBy(control_endpoint):
438        to_try = [control_endpoint]
439    elif isinstance(control_endpoint, Sequence):
440        to_try = control_endpoint
441        for ep in control_endpoint:
442            if not IStreamClientEndpoint.providedBy(ep):
443                raise ValueError(
444                    "For control_endpoint=, '{}' must provide"
445                    " IStreamClientEndpoint".format(ep)
446                )
447    else:
448        raise ValueError(
449            "For control_endpoint=, '{}' must provide"
450            " IStreamClientEndpoint".format(control_endpoint)
451        )
452
453    errors = []
454    for idx, ep in enumerate(to_try):
455        try:
456            tor = yield try_endpoint(ep)
457            txtorlog.msg("Connected via '{}'".format(ep))
458            returnValue(tor)
459        except Exception as e:
460            errors.append(e)
461    if len(errors) == 1:
462        raise errors[0]
463    raise RuntimeError(
464        'Failed to connect to: {}'.format(
465            ', '.join(
466                '{}: {}'.format(ep, err) for ep, err in zip(to_try, errors)
467            )
468        )
469    )
470
471
472@implementer(ITor)
473class Tor(object):
474    """
475    I represent a single instance of Tor and act as a Builder/Factory
476    for several useful objects you will probably want. There are two
477    ways to create a Tor instance:
478
479       - :func:`txtorcon.connect` to connect to a Tor that is already
480         running (e.g. Tor Browser Bundle, a system Tor, ...).
481       - :func:`txtorcon.launch` to launch a fresh Tor instance
482
483    The stable API provided by this class is :class:`txtorcon.interface.ITor`
484
485    If you desire more control, there are "lower level" APIs which are
486    the very ones used by this class. However, this "highest level"
487    API should cover many use-cases::
488
489        import txtorcon
490
491        @inlineCallbacks
492        def main(reactor):
493            # tor = yield txtorcon.connect(UNIXClientEndpoint(reactor, "/var/run/tor/control"))
494            tor = yield txtorcon.launch(reactor)
495
496            onion_ep = tor.create_onion_endpoint(port=80)
497            port = yield onion_ep.listen(Site())
498            print(port.getHost())
499    """
500
501    def __init__(self, reactor, control_protocol, _tor_config=None, _process_proto=None, _non_anonymous=None):
502        """
503        don't instantiate this class yourself -- instead use the factory
504        methods :func:`txtorcon.launch` or :func:`txtorcon.connect`
505        """
506        self._protocol = control_protocol
507        self._config = _tor_config
508        self._reactor = reactor
509        # this only passed/set when we launch()
510        self._process_protocol = _process_proto
511        # cache our preferred socks port (please use
512        # self._default_socks_endpoint() to get one)
513        self._socks_endpoint = None
514        # True if we've turned on non-anonymous mode / Onion services
515        self._non_anonymous = _non_anonymous
516
517    @inlineCallbacks
518    def quit(self):
519        """
520        Closes the control connection, and if we launched this Tor
521        instance we'll send it a TERM and wait until it exits.
522        """
523        if self._protocol is not None:
524            yield self._protocol.quit()
525        if self._process_protocol is not None:
526            yield self._process_protocol.quit()
527        if self._protocol is None and self._process_protocol is None:
528            raise RuntimeError(
529                "This Tor has no protocol instance; we can't quit"
530            )
531        if self._protocol is not None:
532            yield self._protocol.on_disconnect
533
534    @property
535    def process(self):
536        """
537        An object implementing
538        :api:`twisted.internet.interfaces.IProcessProtocol` if this
539        Tor instance was launched, or None.
540        """
541        if self._process_protocol:
542            return self._process_protocol
543        return None
544
545    @property
546    def protocol(self):
547        """
548        The TorControlProtocol instance that is communicating with this
549        Tor instance.
550        """
551        return self._protocol
552
553    @property
554    def version(self):
555        return self._protocol.version
556
557    @inlineCallbacks
558    def get_config(self):
559        """
560        :return: a Deferred that fires with a TorConfig instance. This
561            instance represents up-to-date configuration of the tor
562            instance (even if another controller is connected). If you
563            call this more than once you'll get the same TorConfig back.
564        """
565        if self._config is None:
566            self._config = yield TorConfig.from_protocol(self._protocol)
567        returnValue(self._config)
568
569    def web_agent(self, pool=None, socks_endpoint=None):
570        """
571        :param socks_endpoint: If ``None`` (the default), a suitable
572            SOCKS port is chosen from our config (or added). If supplied,
573            should be a Deferred which fires an IStreamClientEndpoint
574            (e.g. the return-value from
575            :meth:`txtorcon.TorConfig.socks_endpoint`) or an immediate
576            IStreamClientEndpoint You probably don't need to mess with
577            this.
578
579        :param pool: passed on to the Agent (as ``pool=``)
580        """
581        if self._non_anonymous:
582            raise Exception(
583                "Cannot use web_agent when in non_anonymous mode"
584            )
585        # local import since not all platforms have this
586        from txtorcon import web
587
588        if socks_endpoint is None:
589            socks_endpoint = _create_socks_endpoint(self._reactor, self._protocol)
590        if not isinstance(socks_endpoint, Deferred):
591            if not IStreamClientEndpoint.providedBy(socks_endpoint):
592                raise ValueError(
593                    "'socks_endpoint' should be a Deferred or an IStreamClient"
594                    "Endpoint (got '{}')".format(type(socks_endpoint))
595                )
596        return web.tor_agent(
597            self._reactor,
598            socks_endpoint,
599            pool=pool,
600        )
601
602    @inlineCallbacks
603    def dns_resolve(self, hostname):
604        """
605        :param hostname: a string
606
607        :returns: a Deferred that calbacks with the hostname as looked-up
608            via Tor (or errback).  This uses Tor's custom extension to the
609            SOCKS5 protocol.
610        """
611        socks_ep = yield self._default_socks_endpoint()
612        ans = yield socks.resolve(socks_ep, hostname)
613        returnValue(ans)
614
615    @inlineCallbacks
616    def dns_resolve_ptr(self, ip):
617        """
618        :param ip: a string, like "127.0.0.1"
619
620        :returns: a Deferred that calbacks with the IP address as
621            looked-up via Tor (or errback).  This uses Tor's custom
622            extension to the SOCKS5 protocol.
623        """
624        socks_ep = yield self._default_socks_endpoint()
625        ans = yield socks.resolve_ptr(socks_ep, ip)
626        returnValue(ans)
627
628    @inlineCallbacks
629    def add_onion_authentication(self, onion_host, token):
630        """
631        Add a client-side authentication token for a particular Onion
632        service.
633        """
634        # if we add the same onion twice, Tor rejects us. We throw an
635        # error if we already have that .onion but the incoming token
636        # doesn't match
637        if isinstance(onion_host, bytes):
638            onion_host = onion_host.decode('ascii')
639
640        config = yield self.get_config()
641        tokens = {
642            servauth.split()[0]: servauth.split()[1]
643            for servauth in config.HidServAuth
644        }
645        try:
646            maybe_token = tokens[onion_host]
647            if maybe_token != token:
648                raise ValueError(
649                    "Token conflict for host '{}'".format(onion_host)
650                )
651            return
652        except KeyError:
653            pass
654
655        # add our onion + token combo
656        config.HidServAuth.append(
657            u"{} {}".format(onion_host, token)
658        )
659        yield config.save()
660
661    @inlineCallbacks
662    def remove_onion_authentication(self, onion_host):
663        """
664        Remove a token for an onion host
665
666        :returns: True if successful, False if there wasn't a token
667            for that host.
668        """
669        if isinstance(onion_host, bytes):
670            onion_host = onion_host.decode('ascii')
671
672        config = yield self.get_config()
673        to_remove = None
674        for auth in config.HidServAuth:
675            host, token = auth.split()
676            if host == onion_host:
677                to_remove = auth
678
679        if to_remove is not None:
680            config.HidServAuth.remove(to_remove)
681            yield config.save()
682            returnValue(True)
683        returnValue(False)
684
685    def onion_authentication(self, onion_host, token):
686        """
687        (Python3 only!) This returns an async context-manager that will
688        add and remove onion authentication. For example, inside an
689        `async def` method that's had `ensureDeferred` called on it::
690
691            async with tor.onion_authentication("timaq4ygg2iegci7.onion", "seekrit token"):
692                agent = tor.web_agent()
693                resp = await agent.request(b'GET', "http://timaq4ygg2iegci7.onion/")
694                body = await readBody(resp)
695            # after the "async with" the token will be removed from Tor's configuration
696
697        Under the hood, this just uses the add_onion_authentication
698        and remove_onion_authentication methods so on Python2 you can
699        use those together with try/finally to get the same effect.
700        """
701        if not HAVE_ASYNC:
702            raise RuntimeError(
703                "async context-managers not supported in Python3.4 or lower"
704            )
705        return _AsyncOnionAuthContext(
706            self, onion_host, token
707        )
708
709    def stream_via(self, host, port, tls=False, socks_endpoint=None):
710        """
711        This returns an IStreamClientEndpoint_ instance that will use this
712        Tor (via SOCKS) to visit the ``(host, port)`` indicated.
713
714        :param host: The host to connect to. You MUST pass host-names
715            to this. If you absolutely know that you've not leaked DNS
716            (e.g. you save IPs in your app's configuration or similar)
717            then you can pass an IP.
718
719        :param port: Port to connect to.
720
721        :param tls: If True, it will wrap the return endpoint in one
722            that does TLS (default: False).
723
724        :param socks_endpoint: Normally not needed (default: None)
725            but you can pass an IStreamClientEndpoint_ directed at one
726            of the local Tor's SOCKS5 ports (e.g. created with
727            :meth:`txtorcon.TorConfig.create_socks_endpoint`). Can be
728            a Deferred.
729
730        .. _IStreamClientEndpoint: https://twistedmatrix.com/documents/current/api/twisted.internet.interfaces.IStreamClientEndpoint.html
731        """
732        if _is_non_public_numeric_address(host):
733            raise ValueError("'{}' isn't going to work over Tor".format(host))
734
735        if socks_endpoint is None:
736            socks_endpoint = self._default_socks_endpoint()
737        # socks_endpoint may be a a Deferred, but TorClientEndpoint handles it
738        return TorClientEndpoint(
739            host, port,
740            socks_endpoint=socks_endpoint,
741            tls=tls,
742            reactor=self._reactor,
743        )
744
745    def create_authenticated_onion_endpoint(self, port, auth, private_key=None, version=None):
746        """
747        WARNING: API subject to change
748
749        When creating an authenticated Onion service a token is
750        created for each user. For 'stealth' authentication, the
751        hostname is also different for each user. The difference between
752        this method and :meth:`txtorcon.Tor.create_onion_endpoint` is
753        in this case the "onion_service" instance implements
754        :class:`txtorcon.IAuthenticatedOnionClients`.
755
756        :returns: an object that implements IStreamServerEndpoint,
757            which will create an "ephemeral" Onion service when
758            ``.listen()`` is called. This uses the ``ADD_ONION`` Tor
759            control-protocol command. The object returned from
760            ``.listen()`` will be a :class:TorOnionListeningPort``;
761            its ``.onion_service`` attribute will be a
762            :class:`txtorcon.IAuthenticatedOnionClients` instance.
763
764        :param port: the port to listen publically on the Tor network
765           on (e.g. 80 for a Web server)
766
767        :param private_key: if not None (the default), this should be
768            the same blob of key material that you received from the
769            :class:`txtorcon.IOnionService` object during a previous
770            run (i.e. from the ``.provate_key`` attribute).
771
772        :param version: if not None, a specific version of service to
773            use; version=3 is Proposition 224 and version=2 is the
774            older 1024-bit key based implementation.
775
776        :param auth: a AuthBasic or AuthStealth instance
777        """
778        return TCPHiddenServiceEndpoint(
779            self._reactor, self.get_config(), port,
780            hidden_service_dir=None,
781            local_port=None,
782            ephemeral=True,
783            private_key=private_key,
784            version=version,
785            auth=auth,
786        )
787
788    def create_onion_endpoint(self, port, private_key=None, version=None, single_hop=None):
789        """
790        WARNING: API subject to change
791
792        :returns: an object that implements IStreamServerEndpoint,
793            which will create an "ephemeral" Onion service when
794            ``.listen()`` is called. This uses the ``ADD_ONION`` tor
795            control-protocol command. The object returned from
796            ``.listen()`` will be a :class:TorOnionListeningPort``;
797            its ``.onion_service`` attribute will be a
798            :class:`txtorcon.IOnionService` instance.
799
800        :param port: the port to listen publically on the Tor network
801           on (e.g. 80 for a Web server)
802
803        :param private_key: if not None (the default), this should be
804            the same blob of key material that you received from the
805            :class:`txtorcon.IOnionService` object during a previous
806            run (i.e. from the ``.private_key`` attribute).
807
808        :param version: if not None, a specific version of service to
809            use; version=3 is Proposition 224 and version=2 is the
810            older 1024-bit key based implementation.
811
812        :param single_hop: if True, pass the `NonAnonymous` flag. Note
813            that Tor options `HiddenServiceSingleHopMode`,
814            `HiddenServiceNonAnonymousMode` must be set to `1` and there
815            must be no `SOCKSPort` configured for this to actually work.
816        """
817        # note, we're just depending on this being The Ultimate
818        # Everything endpoint. Which seems fine, because "normal"
819        # users should use this or another factory-method to
820        # instantiate them...
821        return TCPHiddenServiceEndpoint(
822            self._reactor, self.get_config(), port,
823            hidden_service_dir=None,
824            local_port=None,
825            ephemeral=True,
826            private_key=private_key,
827            version=version,
828            auth=None,
829            single_hop=single_hop,
830        )
831
832    def create_filesystem_onion_endpoint(self, port, hs_dir, group_readable=False, version=None):
833        """
834        WARNING: API subject to change
835
836        :returns: an object that implements IStreamServerEndpoint. When
837            the ``.listen()`` method is called, the endpoint will create
838            an Onion service whose keys are on disk when ``.listen()`` is
839            called. The object returned from ``.listen()`` will be a
840            :class:TorOnionListeningPort``; its ``.onion_service``
841            attribute will be a :class:`txtorcon.IOnionService` instance.
842
843        :param port: the port to listen publically on the Tor network
844           on (e.g. 80 for a Web server)
845
846        :param hs_dir: the directory in which keys are stored for this
847            service.
848
849        :param group_readable: controls the Tor
850            `HiddenServiceDirGroupReadable` which will either set (or not)
851            group read-permissions on the hs_dir.
852
853        :param version: if not None, a specific version of service to
854            use; version=3 is Proposition 224 and version=2 is the
855            older 1024-bit key based implementation. The default is version 3.
856        """
857        return TCPHiddenServiceEndpoint(
858            self._reactor, self.get_config(), port,
859            hidden_service_dir=hs_dir,
860            local_port=None,
861            ephemeral=False,
862            private_key=None,
863            group_readable=int(group_readable),
864            version=version,
865            auth=None,
866        )
867
868    def create_filesystem_authenticated_onion_endpoint(self, port, hs_dir, auth, group_readable=False, version=None):
869        """
870        WARNING: API subject to change
871
872        :returns: an object that implements IStreamServerEndpoint. When
873            the ``.listen()`` method is called, the endpoint will create
874            an Onion service whose keys are on disk when ``.listen()`` is
875            called. The object returned from ``.listen()`` will be a
876            :class:TorOnionListeningPort``; its ``.onion_service``
877            attribute will be a :class:`txtorcon.IOnionService` instance.
878
879        :param port: the port to listen publically on the Tor network
880           on (e.g. 80 for a Web server)
881
882        :param hs_dir: the directory in which keys are stored for this
883            service.
884
885        :param auth: instance of :class:`txtorcon.AuthBasic` or
886            :class:`txtorcon.AuthStealth` controlling the type of
887            authentication to use.
888
889        :param group_readable: controls the Tor
890            `HiddenServiceDirGroupReadable` which will either set (or not)
891            group read-permissions on the hs_dir.
892
893        :param version: if not None, a specific version of service to
894            use; version=3 is Proposition 224 and version=2 is the
895            older 1024-bit key based implementation. The default is version 3.
896        """
897        return TCPHiddenServiceEndpoint(
898            self._reactor, self.get_config(), port,
899            hidden_service_dir=hs_dir,
900            local_port=None,
901            ephemeral=False,
902            private_key=None,
903            group_readable=int(group_readable),
904            version=version,
905            auth=auth,
906        )
907
908    # XXX or get_state()? and make there be always 0 or 1 states; cf. convo w/ Warner
909    @inlineCallbacks
910    def create_state(self):
911        """
912        returns a Deferred that fires with a ready-to-go
913        :class:`txtorcon.TorState` instance.
914        """
915        state = TorState(self.protocol)
916        yield state.post_bootstrap
917        returnValue(state)
918
919    def __str__(self):
920        return "<Tor version='{tor_version}'>".format(
921            tor_version=self._protocol.version,
922        )
923
924    @inlineCallbacks
925    def is_ready(self):
926        """
927        :return: a Deferred that fires with True if this Tor is
928            non-dormant and ready to go. This will return True if `GETINFO
929            dormant` is false or if `GETINFO status/enough-dir-info` is
930            true or if `GETINFO status/circuit-established` true.
931        """
932        info = yield self.protocol.get_info(
933            "dormant",
934            "status/enough-dir-info",
935            "status/circuit-established",
936        )
937        returnValue(
938            not(
939                int(info["dormant"]) or
940                not int(info["status/enough-dir-info"]) or
941                not int(info["status/circuit-established"])
942            )
943        )
944
945    @inlineCallbacks
946    def become_ready(self):
947        """
948        Make sure Tor is no longer dormant.
949
950        If Tor is currently dormant, it is woken up by doing a DNS
951        request for torproject.org
952        """
953        ready = yield self.is_ready()
954        if not ready:
955            yield self.dns_resolve(u'torproject.org')
956        return
957
958    @inlineCallbacks
959    def _default_socks_endpoint(self):
960        """
961        Returns a Deferred that fires with our default SOCKS endpoint
962        (which might mean setting one up in our attacked Tor if it
963        doesn't have one)
964        """
965        if self._non_anonymous:
966            raise Exception(
967                "Cannot use SOCKS when in non_anonymous mode"
968            )
969        if self._socks_endpoint is None:
970            self._socks_endpoint = yield _create_socks_endpoint(self._reactor, self._protocol)
971        returnValue(self._socks_endpoint)
972
973    # For all these create_*() methods, instead of magically computing
974    # the class-name from arguments (e.g. we could decide "it's a
975    # Filesystem thing" if "hidden_service_dir=" is passed) we have an
976    # explicit method for each type of service. This means each method
977    # always returns the same type of object (good!) and user-code is
978    # more explicit about what they want (also good!) .. but the
979    # method names are kind of long (not-ideal)
980
981    @inlineCallbacks
982    def create_onion_service(self, ports, private_key=None, version=3,
983                             progress=None, await_all_uploads=False,
984                             single_hop=None, detach=None):
985        """
986        Create a new Onion service
987
988        This method will create a new Onion service, returning (via
989        Deferred) an instance that implements IOnionService. (To
990        create authenticated onion services, see XXX). This method
991        awaits at least one upload of the Onion service's 'descriptor'
992        to the Tor network -- this can take from 30s to a couple
993        minutes.
994
995        :param private_key: None, ``txtorcon.DISCARD`` or a key-blob
996            retained from a prior run
997
998            Passing ``None`` means a new one will be created. It can be
999            retrieved from the ``.private_key`` property of the returned
1000            object. You **must** retain this key yourself (and pass it in
1001            to this method in the future) if you wish to keep the same
1002            ``.onion`` domain when re-starting your program.
1003
1004            Passing ``txtorcon.DISCARD`` means txtorcon will never learn the
1005            private key from Tor and so there will be no way to re-create
1006            an Onion Service on the same address after Tor exits.
1007
1008        :param version: The latest Tor releases support 'Proposition
1009            224' (version 3) services. These are the default.
1010
1011        :param progress: if provided, a function that takes 3
1012            arguments: ``(percent_done, tag, description)`` which may
1013            be called any number of times to indicate some progress has
1014            been made.
1015
1016        :param await_all_uploads: if False (the default) then we wait
1017            until at least one upload of our Descriptor to a Directory
1018            Authority has completed; if True we wait until all have
1019            completed.
1020
1021        :param single_hop: if True, pass the `NonAnonymous` flag. Note
1022            that Tor options `HiddenServiceSingleHopMode`,
1023            `HiddenServiceNonAnonymousMode` must be set to `1` and there
1024            must be no `SOCKSPort` configured for this to actually work.
1025
1026        :param detach: if True, the created service won't be tied to
1027            this control connection and will still be active when this
1028            control-connection goes away (this means the service will
1029            appear in `GETINFO onions/detached` to all other
1030            controllers)
1031        """
1032        if version not in (2, 3):
1033            raise ValueError(
1034                "The only valid Onion service versions are 2 or 3"
1035            )
1036        if not isinstance(ports, Sequence) or isinstance(ports, six.string_types):
1037            raise ValueError("'ports' must be a sequence (list, tuple, ..)")
1038
1039        processed_ports = yield _validate_ports(self._reactor, ports)
1040        config = yield self.get_config()
1041        service = yield EphemeralOnionService.create(
1042            reactor=self._reactor,
1043            config=config,
1044            ports=processed_ports,
1045            private_key=private_key,
1046            version=version,
1047            progress=progress,
1048            await_all_uploads=await_all_uploads,
1049            single_hop=single_hop,
1050            detach=detach,
1051        )
1052        returnValue(service)
1053
1054    @inlineCallbacks
1055    def create_filesystem_onion_service(self, ports, onion_service_dir,
1056                                        version=3,
1057                                        group_readable=False,
1058                                        progress=None,
1059                                        await_all_uploads=False):
1060        """Create a new Onion service stored on disk
1061
1062        This method will create a new Onion service, returning (via
1063        Deferred) an instance that implements IOnionService. (To
1064        create authenticated onion services, see XXX). This method
1065        awaits at least one upload of the Onion service's 'descriptor'
1066        to the Tor network -- this can take from 30s to a couple
1067        minutes.
1068
1069        :param ports: a collection of ports to advertise; these are
1070            forwarded locally on a random port. Each entry may instead be
1071            a 2-tuple, which chooses an explicit local port.
1072
1073        :param onion_service_dir: a path to an Onion Service
1074            directory.
1075
1076            Tor will write a ``hostname`` file in this directory along
1077            with the private keys for the service (if they do not already
1078            exist). You do not need to retain the private key yourself.
1079
1080        :param version: which kind of Onion Service to create. The
1081            default is ``3`` which are the Proposition 224
1082            services. Version ``2`` are the previous services. There are
1083            no other valid versions currently.
1084
1085        :param group_readable: if True, Tor creates the directory with
1086           group read permissions. The default is False.
1087
1088        :param progress: if provided, a function that takes 3
1089            arguments: ``(percent_done, tag, description)`` which may
1090            be called any number of times to indicate some progress has
1091            been made.
1092
1093        """
1094        if not isinstance(ports, Sequence) or isinstance(ports, six.string_types):
1095            raise ValueError("'ports' must be a sequence (list, tuple, ..)")
1096        processed_ports = yield _validate_ports(self._reactor, ports)
1097
1098        if version not in (2, 3):
1099            raise ValueError(
1100                "The only valid Onion service versions are 2 or 3"
1101            )
1102        config = yield self.get_config()
1103        service = yield FilesystemOnionService.create(
1104            reactor=self._reactor,
1105            config=config,
1106            hsdir=onion_service_dir,
1107            ports=processed_ports,
1108            version=version,
1109            group_readable=group_readable,
1110            progress=progress,
1111            await_all_uploads=await_all_uploads,
1112        )
1113        returnValue(service)
1114
1115
1116class TorNotFound(RuntimeError):
1117    """
1118    Raised by launch_tor() in case the tor binary was unspecified and could
1119    not be found by consulting the shell.
1120    """
1121
1122
1123class TorProcessProtocol(protocol.ProcessProtocol):
1124
1125    def __init__(self, connection_creator, progress_updates=None, config=None,
1126                 ireactortime=None, timeout=None, kill_on_stderr=True,
1127                 stdout=None, stderr=None):
1128        """
1129        This will read the output from a Tor process and attempt a
1130        connection to its control port when it sees any 'Bootstrapped'
1131        message on stdout. You probably don't need to use this
1132        directly except as the return value from the
1133        :func:`txtorcon.launch_tor` method. tor_protocol contains a
1134        valid :class:`txtorcon.TorControlProtocol` instance by that
1135        point.
1136
1137        connection_creator is a callable that should return a Deferred
1138        that callbacks with a :class:`txtorcon.TorControlProtocol`;
1139        see :func:`txtorcon.launch_tor` for the default one which is a
1140        functools.partial that will call
1141        ``connect(TorProtocolFactory())`` on an appropriate
1142        :api:`twisted.internet.endpoints.TCP4ClientEndpoint`
1143
1144        :param connection_creator: A no-parameter callable which
1145            returns a Deferred which promises a
1146            :api:`twisted.internet.interfaces.IStreamClientEndpoint
1147            <IStreamClientEndpoint>`. If this is None, we do NOT
1148            attempt to connect to the underlying Tor process.
1149
1150        :param progress_updates: A callback which received progress
1151            updates with three args: percent, tag, summary
1152
1153        :param config: a TorConfig object to connect to the
1154            TorControlProtocl from the launched tor (should it succeed)
1155
1156        :param ireactortime:
1157            An object implementing IReactorTime (i.e. a reactor) which
1158            needs to be supplied if you pass a timeout.
1159
1160        :param timeout:
1161            An int representing the timeout in seconds. If we are
1162            unable to reach 100% by this time we will consider the
1163            setting up of Tor to have failed. Must supply ireactortime
1164            if you supply this.
1165
1166        :param kill_on_stderr:
1167            When True, kill subprocess if we receive anything on stderr
1168
1169        :param stdout:
1170            Anything subprocess writes to stdout is sent to .write() on this
1171
1172        :param stderr:
1173            Anything subprocess writes to stderr is sent to .write() on this
1174
1175        :ivar tor_protocol: The TorControlProtocol instance connected
1176            to the Tor this
1177            :api:`twisted.internet.protocol.ProcessProtocol
1178            <ProcessProtocol>`` is speaking to. Will be valid after
1179            the Deferred returned from
1180            :meth:`TorProcessProtocol.when_connected` is triggered.
1181        """
1182
1183        self.config = config
1184        self.tor_protocol = None
1185        self.progress_updates = progress_updates
1186
1187        # XXX if connection_creator is not None .. is connected_cb
1188        # tied to connection_creator...?
1189        if connection_creator:
1190            self.connection_creator = connection_creator
1191        else:
1192            self.connection_creator = None
1193        # use SingleObserver
1194        self._connected_listeners = []  # list of Deferred (None when we're connected)
1195
1196        self.attempted_connect = False
1197        self.to_delete = []
1198        self.kill_on_stderr = kill_on_stderr
1199        self.stderr = stderr
1200        self.stdout = stdout
1201        self.collected_stdout = StringIO()
1202
1203        self._setup_complete = False
1204        self._did_timeout = False
1205        self._timeout_delayed_call = None
1206        self._on_exit = []  # Deferred's we owe a call/errback to when we exit
1207        if timeout:
1208            if not ireactortime:
1209                raise RuntimeError(
1210                    'Must supply an IReactorTime object when supplying a '
1211                    'timeout')
1212            ireactortime = IReactorTime(ireactortime)
1213            self._timeout_delayed_call = ireactortime.callLater(
1214                timeout, self._timeout_expired)
1215
1216    def when_connected(self):
1217        if self._connected_listeners is None:
1218            return succeed(self)
1219        d = Deferred()
1220        self._connected_listeners.append(d)
1221        return d
1222
1223    def _maybe_notify_connected(self, arg):
1224        """
1225        Internal helper.
1226
1227        .callback or .errback on all Deferreds we've returned from
1228        `when_connected`
1229        """
1230        if self._connected_listeners is None:
1231            return
1232        for d in self._connected_listeners:
1233            # Twisted will turn this into an errback if "arg" is a
1234            # Failure
1235            d.callback(arg)
1236        self._connected_listeners = None
1237
1238    def quit(self):
1239        """
1240        This will terminate (with SIGTERM) the underlying Tor process.
1241
1242        :returns: a Deferred that callback()'s (with None) when the
1243            process has actually exited.
1244        """
1245
1246        try:
1247            self.transport.signalProcess('TERM')
1248            d = Deferred()
1249            self._on_exit.append(d)
1250
1251        except error.ProcessExitedAlready:
1252            self.transport.loseConnection()
1253            d = succeed(None)
1254        except Exception:
1255            d = fail()
1256        return d
1257
1258    def _signal_on_exit(self, reason):
1259        to_notify = self._on_exit
1260        self._on_exit = []
1261        for d in to_notify:
1262            d.callback(None)
1263
1264    def outReceived(self, data):
1265        """
1266        :api:`twisted.internet.protocol.ProcessProtocol <ProcessProtocol>` API
1267        """
1268
1269        if self.stdout:
1270            self.stdout.write(data.decode('ascii'))
1271
1272        # minor hack: we can't try this in connectionMade because
1273        # that's when the process first starts up so Tor hasn't
1274        # opened any ports properly yet. So, we presume that after
1275        # its first output we're good-to-go. If this fails, we'll
1276        # reset and try again at the next output (see this class'
1277        # tor_connection_failed)
1278        txtorlog.msg(data)
1279        if not self.attempted_connect and self.connection_creator \
1280                and b'Opening Control listener' in data:
1281            self.attempted_connect = True
1282            # hmmm, we don't "do" anything with this Deferred?
1283            # (should it be connected to the when_connected
1284            # Deferreds?)
1285            d = self.connection_creator()
1286            d.addCallback(self._tor_connected)
1287            d.addErrback(self._tor_connection_failed)
1288# XXX 'should' be able to improve the error-handling by directly tying
1289# this Deferred into the notifications -- BUT we might try again, so
1290# we need to know "have we given up -- had an error" and only in that
1291# case send to the connected things. I think?
1292#            d.addCallback(self._maybe_notify_connected)
1293
1294    def _timeout_expired(self):
1295        """
1296        A timeout was supplied during setup, and the time has run out.
1297        """
1298        self._did_timeout = True
1299        try:
1300            self.transport.signalProcess('TERM')
1301        except error.ProcessExitedAlready:
1302            # XXX why don't we just always do this?
1303            self.transport.loseConnection()
1304
1305        fail = Failure(RuntimeError("timeout while launching Tor"))
1306        self._maybe_notify_connected(fail)
1307
1308    def errReceived(self, data):
1309        """
1310        :api:`twisted.internet.protocol.ProcessProtocol <ProcessProtocol>` API
1311        """
1312
1313        if self.stderr:
1314            self.stderr.write(data)
1315
1316        if self.kill_on_stderr:
1317            self.transport.loseConnection()
1318            raise RuntimeError(
1319                "Received stderr output from slave Tor process: " + data.decode('utf8')
1320            )
1321
1322    def cleanup(self):
1323        """
1324        Clean up my temporary files.
1325        """
1326
1327        all([delete_file_or_tree(f) for f in self.to_delete])
1328        self.to_delete = []
1329
1330    def processExited(self, reason):
1331        self._signal_on_exit(reason)
1332
1333    def processEnded(self, status):
1334        """
1335        :api:`twisted.internet.protocol.ProcessProtocol <ProcessProtocol>` API
1336        """
1337        self.cleanup()
1338
1339        if status.value.exitCode is None:
1340            if self._did_timeout:
1341                err = RuntimeError("Timeout waiting for Tor launch.")
1342            else:
1343                err = RuntimeError(
1344                    "Tor was killed (%s)." % status.value.signal)
1345        else:
1346            err = RuntimeError(
1347                "Tor exited with error-code %d" % status.value.exitCode)
1348
1349        # hmmm, this log() should probably go away...not always an
1350        # error (e.g. .quit()
1351        log.err(err)
1352        self._maybe_notify_connected(Failure(err))
1353
1354    def progress(self, percent, tag, summary):
1355        """
1356        Can be overridden or monkey-patched if you want to get
1357        progress updates yourself.
1358        """
1359
1360        if self.progress_updates:
1361            self.progress_updates(percent, tag, summary)
1362
1363    # the below are all callbacks
1364
1365    def _tor_connection_failed(self, failure):
1366        # FIXME more robust error-handling please, like a timeout so
1367        # we don't just wait forever after 100% bootstrapped (that
1368        # is, we're ignoring these errors, but shouldn't do so after
1369        # we'll stop trying)
1370        # XXX also, should check if the failure is e.g. a syntax error
1371        # or an actually connection failure
1372
1373        # okay, so this is a little trickier than I thought at first:
1374        # we *can* just relay this back to the
1375        # connection_creator()-returned Deferred, *but* we don't know
1376        # if this is "the last" error and we're going to try again
1377        # (and thus e.g. should fail all the when_connected()
1378        # Deferreds) or not.
1379        log.err(failure)
1380        self.attempted_connect = False
1381        return None
1382
1383    def _status_client(self, arg):
1384        args = shlex.split(arg)
1385        if args[1] != 'BOOTSTRAP':
1386            return
1387
1388        kw = find_keywords(args)
1389        prog = int(kw['PROGRESS'])
1390        tag = kw['TAG']
1391        summary = kw['SUMMARY']
1392        self.progress(prog, tag, summary)
1393
1394        if prog == 100:
1395            if self._timeout_delayed_call:
1396                self._timeout_delayed_call.cancel()
1397                self._timeout_delayed_call = None
1398            self._maybe_notify_connected(self)
1399
1400    @inlineCallbacks
1401    def _tor_connected(self, proto):
1402        txtorlog.msg("tor_connected %s" % proto)
1403
1404        self.tor_protocol = proto
1405        self.tor_protocol.is_owned = self.transport.pid
1406
1407        yield self.tor_protocol.post_bootstrap
1408        txtorlog.msg("Protocol is bootstrapped")
1409        yield self.tor_protocol.add_event_listener('STATUS_CLIENT', self._status_client)
1410        yield self.tor_protocol.queue_command('TAKEOWNERSHIP')
1411        yield self.tor_protocol.queue_command('RESETCONF __OwningControllerProcess')
1412        if self.config is not None and self.config.protocol is None:
1413            yield self.config.attach_protocol(proto)
1414        returnValue(self)  # XXX or "proto"?
1415