Exemplo n.º 1
0
def _create_transport_endpoint(reactor, endpoint_config):
    """
    Create a Twisted client endpoint for a WAMP-over-XXX transport.
    """
    if IStreamClientEndpoint.providedBy(endpoint_config):
        endpoint = IStreamClientEndpoint(endpoint_config)
    else:
        # create a connecting TCP socket
        if endpoint_config['type'] == 'tcp':

            version = int(endpoint_config.get('version', 4))
            host = str(endpoint_config['host'])
            port = int(endpoint_config['port'])
            timeout = int(endpoint_config.get('timeout', 10))  # in seconds
            tls = endpoint_config.get('tls', None)

            # create a TLS enabled connecting TCP socket
            if tls:
                if not _TLS:
                    raise RuntimeError(
                        'TLS configured in transport, but TLS support is not installed (eg OpenSSL?)'
                    )

                # FIXME: create TLS context from configuration
                if IOpenSSLClientComponentCreator.providedBy(tls):
                    # eg created from twisted.internet.ssl.optionsForClientTLS()
                    context = IOpenSSLClientComponentCreator(tls)

                elif isinstance(tls, CertificateOptions):
                    context = tls

                elif tls is True:
                    context = optionsForClientTLS(host)

                else:
                    raise RuntimeError(
                        'unknown type {} for "tls" configuration in transport'.
                        format(type(tls)))

                if version == 4:
                    endpoint = SSL4ClientEndpoint(reactor,
                                                  host,
                                                  port,
                                                  context,
                                                  timeout=timeout)
                elif version == 6:
                    # there is no SSL6ClientEndpoint!
                    raise RuntimeError('TLS on IPv6 not implemented')
                else:
                    assert (False), 'should not arrive here'

            # create a non-TLS connecting TCP socket
            else:
                if version == 4:
                    endpoint = TCP4ClientEndpoint(reactor,
                                                  host,
                                                  port,
                                                  timeout=timeout)
                elif version == 6:
                    try:
                        from twisted.internet.endpoints import TCP6ClientEndpoint
                    except ImportError:
                        raise RuntimeError(
                            'IPv6 is not supported (please upgrade Twisted)')
                    endpoint = TCP6ClientEndpoint(reactor,
                                                  host,
                                                  port,
                                                  timeout=timeout)
                else:
                    assert (False), 'should not arrive here'

        # create a connecting Unix domain socket
        elif endpoint_config['type'] == 'unix':
            path = endpoint_config['path']
            timeout = int(endpoint_config.get('timeout', 10))  # in seconds
            endpoint = UNIXClientEndpoint(reactor, path, timeout=timeout)

        else:
            assert (False), 'should not arrive here'

    return endpoint
Exemplo n.º 2
0
def connect_to_control_port():
    connection = TCP4ClientEndpoint(reactor, '127.0.0.1',
                                    config.tor.control_port)
    config.tor_state = yield build_tor_connection(connection)
Exemplo n.º 3
0
                      default=7000)

    parser.add_option('--num',
                      '-n',
                      action='store',
                      dest='numOrders',
                      type='int',
                      help='Number of orders',
                      metavar='N',
                      default=100000)

    parser.add_option('--print',
                      '-p',
                      action='store_true',
                      dest='print_messages',
                      help='Print messages',
                      default=False)

    return parser.parse_args(args=None, values=None)


if __name__ == '__main__':
    options, args = parse_options()

    endpoint = TCP4ClientEndpoint(reactor, options.host, options.port)
    endpoint.connect(TraderFactory(options))

    reactor.run()

# EOF
Exemplo n.º 4
0
    def run(self, make, start_reactor=True, auto_reconnect=False, log_level='info', endpoint=None, reactor=None):
        """
        Run the application component.

        :param make: A factory that produces instances of :class:`autobahn.twisted.wamp.ApplicationSession`
           when called with an instance of :class:`autobahn.wamp.types.ComponentConfig`.
        :type make: callable

        :param start_reactor: When ``True`` (the default) this method starts
           the Twisted reactor and doesn't return until the reactor
           stops. If there are any problems starting the reactor or
           connect()-ing, we stop the reactor and raise the exception
           back to the caller.

        :returns: None is returned, unless you specify
            ``start_reactor=False`` in which case the Deferred that
            connect() returns is returned; this will callback() with
            an IProtocol instance, which will actually be an instance
            of :class:`WampWebSocketClientProtocol`
        """
        self.log.debug('{klass}.run()', klass=self.__class__.__name__)

        if start_reactor:
            # only select framework, set loop and start logging when we are asked
            # start the reactor - otherwise we are running in a program that likely
            # already tool care of all this.
            from twisted.internet import reactor
            txaio.use_twisted()
            txaio.config.loop = reactor
            txaio.start_logging(level=log_level)

        if callable(make):
            # factory for use ApplicationSession
            def create():
                cfg = ComponentConfig(self.realm, self.extra, runner=self)
                try:
                    session = make(cfg)
                except Exception:
                    self.log.failure('ApplicationSession could not be instantiated: {log_failure.value}')
                    if start_reactor and reactor.running:
                        reactor.stop()
                    raise
                else:
                    return session
        else:
            create = make

        if self.url.startswith(u'rs'):
            # try to parse RawSocket URL ..
            isSecure, host, port = parse_rs_url(self.url)

            # use the first configured serializer if any (which means, auto-choose "best")
            serializer = self.serializers[0] if self.serializers else None

            # create a WAMP-over-RawSocket transport client factory
            transport_factory = WampRawSocketClientFactory(create, serializer=serializer)

        else:
            # try to parse WebSocket URL ..
            isSecure, host, port, resource, path, params = parse_ws_url(self.url)

            # create a WAMP-over-WebSocket transport client factory
            transport_factory = WampWebSocketClientFactory(create, url=self.url, serializers=self.serializers, proxy=self.proxy, headers=self.headers)

            # client WebSocket settings - similar to:
            # - http://crossbar.io/docs/WebSocket-Compression/#production-settings
            # - http://crossbar.io/docs/WebSocket-Options/#production-settings

            # The permessage-deflate extensions offered to the server ..
            offers = [PerMessageDeflateOffer()]

            # Function to accept permessage_delate responses from the server ..
            def accept(response):
                if isinstance(response, PerMessageDeflateResponse):
                    return PerMessageDeflateResponseAccept(response)

            # set WebSocket options for all client connections
            transport_factory.setProtocolOptions(maxFramePayloadSize=1048576,
                                                 maxMessagePayloadSize=1048576,
                                                 autoFragmentSize=65536,
                                                 failByDrop=False,
                                                 openHandshakeTimeout=2.5,
                                                 closeHandshakeTimeout=1.,
                                                 tcpNoDelay=True,
                                                 autoPingInterval=10.,
                                                 autoPingTimeout=5.,
                                                 autoPingSize=4,
                                                 perMessageCompressionOffers=offers,
                                                 perMessageCompressionAccept=accept)

        # supress pointless log noise
        transport_factory.noisy = False

        if endpoint:
            client = endpoint
        else:
            # if user passed ssl= but isn't using isSecure, we'll never
            # use the ssl argument which makes no sense.
            context_factory = None
            if self.ssl is not None:
                if not isSecure:
                    raise RuntimeError(
                        'ssl= argument value passed to %s conflicts with the "ws:" '
                        'prefix of the url argument. Did you mean to use "wss:"?' %
                        self.__class__.__name__)
                context_factory = self.ssl
            elif isSecure:
                from twisted.internet.ssl import optionsForClientTLS
                context_factory = optionsForClientTLS(host)

            from twisted.internet import reactor
            if self.proxy is not None:
                from twisted.internet.endpoints import TCP4ClientEndpoint
                client = TCP4ClientEndpoint(reactor, self.proxy['host'], self.proxy['port'])
                transport_factory.contextFactory = context_factory
            elif isSecure:
                from twisted.internet.endpoints import SSL4ClientEndpoint
                assert context_factory is not None
                client = SSL4ClientEndpoint(reactor, host, port, context_factory)
            else:
                from twisted.internet.endpoints import TCP4ClientEndpoint
                client = TCP4ClientEndpoint(reactor, host, port)

        # as the reactor shuts down, we wish to wait until we've sent
        # out our "Goodbye" message; leave() returns a Deferred that
        # fires when the transport gets to STATE_CLOSED
        def cleanup(proto):
            if hasattr(proto, '_session') and proto._session is not None:
                if proto._session.is_attached():
                    return proto._session.leave()
                elif proto._session.is_connected():
                    return proto._session.disconnect()

        # when our proto was created and connected, make sure it's cleaned
        # up properly later on when the reactor shuts down for whatever reason
        def init_proto(proto):
            self._connect_successes += 1
            reactor.addSystemEventTrigger('before', 'shutdown', cleanup, proto)
            return proto

        use_service = False
        if auto_reconnect:
            try:
                # since Twisted 16.1.0
                from twisted.application.internet import ClientService
                from twisted.application.internet import backoffPolicy
                use_service = True
            except ImportError:
                use_service = False

        if use_service:
            # this code path is automatically reconnecting ..
            self.log.debug('using t.a.i.ClientService')

            if self.max_retries or self.initial_retry_delay or self.max_retry_delay or self.retry_delay_growth or self.retry_delay_jitter:
                kwargs = {}
                for key, val in [('initialDelay', self.initial_retry_delay),
                                 ('maxDelay', self.max_retry_delay),
                                 ('factor', self.retry_delay_growth),
                                 ('jitter', lambda: random.random() * self.retry_delay_jitter)]:
                    if val:
                        kwargs[key] = val

                # retry policy that will only try to reconnect if we connected
                # successfully at least once before (so it fails on host unreachable etc ..)
                def retry(failed_attempts):
                    if self._connect_successes > 0 and (self.max_retries == -1 or failed_attempts < self.max_retries):
                        return backoffPolicy(**kwargs)(failed_attempts)
                    else:
                        print('hit stop')
                        self.stop()
                        return 100000000000000
            else:
                retry = backoffPolicy()

            self._client_service = ClientService(client, transport_factory, retryPolicy=retry)
            self._client_service.startService()

            d = self._client_service.whenConnected()

        else:
            # this code path is only connecting once!
            self.log.debug('using t.i.e.connect()')

            d = client.connect(transport_factory)

        # if we connect successfully, the arg is a WampWebSocketClientProtocol
        d.addCallback(init_proto)

        # if the user didn't ask us to start the reactor, then they
        # get to deal with any connect errors themselves.
        if start_reactor:
            # if an error happens in the connect(), we save the underlying
            # exception so that after the event-loop exits we can re-raise
            # it to the caller.

            class ErrorCollector(object):
                exception = None

                def __call__(self, failure):
                    self.exception = failure.value
                    reactor.stop()
            connect_error = ErrorCollector()
            d.addErrback(connect_error)

            # now enter the Twisted reactor loop
            reactor.run()

            # if we exited due to a connection error, raise that to the
            # caller
            if connect_error.exception:
                raise connect_error.exception

        else:
            # let the caller handle any errors
            return d
Exemplo n.º 5
0
def main():
    point = TCP4ClientEndpoint(reactor, "35.247.222.99", 5678)
    client = MyClient()
    connectProtocol(point, client)
    reactor.callInThread(MyCmd(client).cmdloop)
    reactor.run()
Exemplo n.º 6
0
def sendmail(to_address, subject, body):
    """
    Sends an email using SMTPS/SMTP+TLS and torify the connection

    @param to_address: the to address field of the email
    @param subject: the mail subject
    @param body: the mail body
    @param event: the event description, needed to keep track of failure/success
    """
    try:
        if not to_address:
            return

        result_deferred = defer.Deferred()

        def errback(reason, *args, **kwargs):
            # TODO: here it should be written a complete debugging of the possible
            #       errors by writing clear log lines in relation to all the stack:
            #       e.g. it should debugged all errors related to: TCP/SOCKS/TLS/SSL/SMTP/SFIGA
            if isinstance(reason, Failure):
                log.err("SMTP connection failed (Exception: %s)", reason.value)
                log.debug(reason)

            return result_deferred.errback(reason)

        result_deferred.addErrback(errback)

        authentication_username = State.tenant_cache[1].notif.username
        authentication_password = State.tenant_cache[1].private.smtp_password
        from_address = State.tenant_cache[1].notif.source_email
        smtp_host = State.tenant_cache[1].notif.server
        smtp_port = State.tenant_cache[1].notif.port
        security = State.tenant_cache[1].notif.security

        message = MIME_mail_build(State.tenant_cache[1].notif.source_name,
                                  State.tenant_cache[1].notif.source_email,
                                  to_address, to_address, subject, body)

        log.debug('Sending email to %s using SMTP server [%s:%d] [%s]',
                  to_address, smtp_host, smtp_port, security)

        context_factory = TLSClientContextFactory()

        factory = ESMTPSenderFactory(
            authentication_username.encode('utf-8'),
            authentication_password.encode('utf-8'),
            from_address,
            to_address,
            message,
            result_deferred,
            contextFactory=context_factory,
            requireAuthentication=True,
            requireTransportSecurity=(security != 'SSL'),
            retries=0,
            timeout=Settings.mail_timeout)

        if security == "SSL":
            factory = tls.TLSMemoryBIOFactory(context_factory, True, factory)

        if State.tenant_cache[1].anonymize_outgoing_connections:
            socksProxy = TCP4ClientEndpoint(reactor,
                                            Settings.socks_host,
                                            Settings.socks_port,
                                            timeout=Settings.mail_timeout)
            endpoint = SOCKS5ClientEndpoint(smtp_host.encode('utf-8'),
                                            smtp_port, socksProxy)
        else:
            endpoint = TCP4ClientEndpoint(reactor,
                                          smtp_host.encode('utf-8'),
                                          smtp_port,
                                          timeout=Settings.mail_timeout)

        if Settings.testing:
            #  Hooking the test down to here is a trick to be able to test all the above code :)
            return defer.succeed(None)

        d = endpoint.connect(factory)
        d.addErrback(errback)

        return result_deferred

    except Exception as excep:
        # we strongly need to avoid raising exception inside email logic to avoid chained errors
        log.err("Unexpected exception in sendmail: %s", str(excep))
        return defer.fail()
Exemplo n.º 7
0
def create_connecting_endpoint_from_config(config, cbdir, reactor, log):
    """
    Create a Twisted stream client endpoint from a Crossbar.io transport configuration.

    See: https://twistedmatrix.com/documents/current/api/twisted.internet.interfaces.IStreamClientEndpoint.html

    :param config: The transport configuration.
    :type config: dict
    :param cbdir: Crossbar.io node directory (we need this for Unix domain socket paths and TLS key/certificates).
    :type cbdir: str
    :param reactor: The reactor to use for endpoint creation.
    :type reactor: obj

    :returns obj -- An instance implementing IStreamClientEndpoint
    """
    endpoint = None

    # a TCP endpoint
    #
    if config['type'] == 'tcp':

        # the TCP protocol version (v4 or v6)
        #
        version = int(config.get('version', 4))

        # the host to connect to
        #
        host = str(config['host'])

        # the port to connect to
        #
        port = int(config['port'])

        # connection timeout in seconds
        #
        timeout = int(config.get('timeout', 10))

        if 'tls' in config:
            # create a TLS client endpoint
            #
            if _HAS_TLS:
                # TLS client context
                context = _create_tls_client_context(config['tls'], cbdir, log)

                if version == 4:
                    endpoint = SSL4ClientEndpoint(
                        reactor,
                        host,
                        port,
                        context,
                        timeout=timeout,
                    )
                elif version == 6:
                    raise Exception("TLS on IPv6 not implemented")
                else:
                    raise Exception(
                        "invalid TCP protocol version {}".format(version))

            else:
                raise Exception(
                    "TLS transport requested, but TLS packages not available:\n{}"
                    .format(_LACKS_TLS_MSG))

        else:
            # create a non-TLS client endpoint
            #
            if version == 4:
                endpoint = TCP4ClientEndpoint(reactor,
                                              host,
                                              port,
                                              timeout=timeout)
            elif version == 6:
                endpoint = TCP6ClientEndpoint(reactor,
                                              host,
                                              port,
                                              timeout=timeout)
            else:
                raise Exception(
                    "invalid TCP protocol version {}".format(version))

    # a Unix Domain Socket endpoint
    #
    elif config['type'] == 'unix':

        # the path
        #
        path = abspath(join(cbdir, config['path']))

        # connection timeout in seconds
        #
        timeout = int(config.get('timeout', 10))

        # create the endpoint
        #
        endpoint = UNIXClientEndpoint(reactor, path, timeout=timeout)

    elif config['type'] == 'twisted':
        endpoint = clientFromString(reactor, config['client_string'])

    elif config['type'] == 'tor':
        host = config['host']
        port = config['port']
        socks_port = config['tor_socks_port']
        tls = config.get('tls', False)
        if not tls and not host.endswith(u'.onion'):
            log.warn(
                "Non-TLS connection traversing Tor network; end-to-end encryption advised"
            )

        socks_endpoint = TCP4ClientEndpoint(
            reactor,
            "127.0.0.1",
            socks_port,
        )
        endpoint = txtorcon.TorClientEndpoint(
            host,
            port,
            socks_endpoint=socks_endpoint,
            reactor=reactor,
            use_tls=tls,
        )

    else:
        raise Exception("invalid endpoint type '{}'".format(config['type']))

    return endpoint
Exemplo n.º 8
0
def launch(
        reactor,
        progress_updates=None,
        control_port=None,
        data_directory=None,
        socks_port=None,
        stdout=None,
        stderr=None,
        timeout=None,
        tor_binary=None,
        user=None,  # XXX like the config['User'] special-casing from before
        # 'users' probably never need these:
    connection_creator=None,
        kill_on_stderr=True,
        _tor_config=None,  # a TorConfig instance, mostly for tests
):
    """
    launches a new Tor process, and returns a Deferred that fires with
    a new :class:`txtorcon.Tor` instance. From this instance, you can
    create or get any "interesting" instances you need: the
    :class:`txtorcon.TorConfig` instance, create endpoints, create
    :class:`txtorcon.TorState` instance(s), etc.

    Note that there is NO way to pass in a config; we only expost a
    couple of basic Tor options. If you need anything beyond these,
    you can access the ``TorConfig`` instance (via ``.config``)
    and make any changes there, reflecting them in tor with
    ``.config.save()``.

    You can igore all the options and safe defaults will be
    provided. However, **it is recommended to pass data_directory**
    especially if you will be starting up Tor frequently, as it saves
    a bunch of time (and bandwidth for the directory
    authorities). "Safe defaults" means:

      - a tempdir for a ``DataDirectory`` is used (respecting ``TMP``)
        and is deleted when this tor is shut down (you therefore
        *probably* want to supply the ``data_directory=`` kwarg);
      - a random, currently-unused local TCP port is used as the
        ``SocksPort`` (specify ``socks_port=`` if you want your
        own). If you want no SOCKS listener at all, pass
        ``socks_port=0``
      - we set ``__OwningControllerProcess`` and call
        ``TAKEOWNERSHIP`` so that if our control connection goes away,
        tor shuts down (see `control-spec
        <https://gitweb.torproject.org/torspec.git/blob/HEAD:/control-spec.txt>`_
        3.23).
      - the launched Tor will use ``COOKIE`` authentication.

    :param reactor: a Twisted IReactorCore implementation (usually
        twisted.internet.reactor)

    :param progress_updates: a callback which gets progress updates; gets 3
         args: percent, tag, summary (FIXME make an interface for this).

    :param data_directory: set as the ``DataDirectory`` option to Tor,
        this is where tor keeps its state information (cached relays,
        etc); starting with an already-populated state directory is a lot
        faster. If ``None`` (the default), we create a tempdir for this
        **and delete it on exit**. It is recommended you pass something here.

    :param stdout: a file-like object to which we write anything that
        Tor prints on stdout (just needs to support write()).

    :param stderr: a file-like object to which we write anything that
        Tor prints on stderr (just needs .write()). Note that we kill
        Tor off by default if anything appears on stderr; pass
        "kill_on_stderr=False" if you don't want this behavior.

    :param tor_binary: path to the Tor binary to run. If None (the
        default), we try to find the tor binary.

    :param kill_on_stderr:
        When True (the default), if Tor prints anything on stderr we
        kill off the process, close the TorControlProtocol and raise
        an exception.

    :param connection_creator: is mostly available to ease testing, so
        you probably don't want to supply this. If supplied, it is a
        callable that should return a Deferred that delivers an
        :api:`twisted.internet.interfaces.IProtocol <IProtocol>` or
        ConnectError.
        See :api:`twisted.internet.interfaces.IStreamClientEndpoint`.connect
        Note that this parameter is ignored if config.ControlPort == 0

    :return: a Deferred which callbacks with :class:`txtorcon.Tor`
        instance, from which you can retrieve the TorControlProtocol
        instance via the ``.protocol`` property.

    HACKS:

     1. It's hard to know when Tor has both (completely!) written its
        authentication cookie file AND is listening on the control
        port. It seems that waiting for the first 'bootstrap' message on
        stdout is sufficient. Seems fragile...and doesn't work 100% of
        the time, so FIXME look at Tor source.



    XXX this "User" thing was, IIRC, a feature for root-using scripts
    (!!) that were going to launch tor, but where tor would drop to a
    different user. Do we still want to support this? Probably
    relevant to Docker (where everything is root! yay!)

    ``User``: if this exists, we attempt to set ownership of the tempdir
    to this user (but only if our effective UID is 0).
    """

    # We have a slight problem with the approach: we need to pass a
    # few minimum values to a torrc file so that Tor will start up
    # enough that we may connect to it. Ideally, we'd be able to
    # start a Tor up which doesn't really do anything except provide
    # "AUTHENTICATE" and "GETINFO config/names" so we can do our
    # config validation.

    if not IReactorCore.providedBy(reactor):
        raise ValueError("'reactor' argument must provide IReactorCore"
                         " (got '{}': {})".format(
                             type(reactor).__class__.__name__, repr(reactor)))

    if tor_binary is None:
        tor_binary = find_tor_binary()
    if tor_binary is None:
        # We fail right here instead of waiting for the reactor to start
        raise TorNotFound('Tor binary could not be found')

    # make sure we got things that have write() for stderr, stdout
    # kwargs (XXX is there a "better" way to check for file-like object?)
    for arg in [stderr, stdout]:
        if arg and not getattr(arg, "write", None):
            raise RuntimeError(
                'File-like object needed for stdout or stderr args.')

    config = _tor_config or TorConfig()
    if data_directory is not None:
        user_set_data_directory = True
        config.DataDirectory = data_directory
        try:
            os.mkdir(data_directory, 0o0700)
        except OSError:
            pass
    else:
        user_set_data_directory = False
        data_directory = tempfile.mkdtemp(prefix='tortmp')
        config.DataDirectory = data_directory
        # note: we also set up the ProcessProtocol to delete this when
        # Tor exits, this is "just in case" fallback:
        reactor.addSystemEventTrigger(
            'before', 'shutdown',
            functools.partial(delete_file_or_tree, data_directory))

    # things that used launch_tor() had to set ControlPort and/or
    # SocksPort on the config to pass them, so we honour that here.
    if control_port is None and _tor_config is not None:
        try:
            control_port = config.ControlPort
        except KeyError:
            control_port = None

    if socks_port is None and _tor_config is not None:
        try:
            socks_port = config.SocksPort
        except KeyError:
            socks_port = None

    if socks_port is None:
        socks_port = yield available_tcp_port(reactor)
    config.SOCKSPort = socks_port

    try:
        our_user = user or config.User
    except KeyError:
        pass
    else:
        if sys.platform in ('linux', 'linux2', 'darwin') and os.geteuid() == 0:
            os.chown(data_directory, pwd.getpwnam(our_user).pw_uid, -1)

    # user can pass in a control port, or we set one up here
    if control_port is None:
        # on posix-y systems, we can use a unix-socket
        if sys.platform in ('linux', 'linux2', 'darwin'):
            # note: tor will not accept a relative path for ControlPort
            control_port = 'unix:{}'.format(
                os.path.join(os.path.realpath(data_directory),
                             'control.socket'))
        else:
            control_port = yield available_tcp_port(reactor)
    else:
        if str(control_port).startswith('unix:'):
            control_path = control_port.lstrip('unix:')
            containing_dir = dirname(control_path)
            if not exists(containing_dir):
                raise ValueError(
                    "The directory containing '{}' must exist".format(
                        containing_dir))
            # Tor will be sad if the directory isn't 0700
            mode = (0o0777 & os.stat(containing_dir).st_mode)
            if mode & ~(0o0700):
                raise ValueError(
                    "The directory containing a unix control-socket ('{}') "
                    "must only be readable by the user".format(containing_dir))
    config.ControlPort = control_port

    config.CookieAuthentication = 1
    config.__OwningControllerProcess = os.getpid()
    if connection_creator is None:
        if str(control_port).startswith('unix:'):
            connection_creator = functools.partial(
                UNIXClientEndpoint(reactor, control_port[5:]).connect,
                TorProtocolFactory())
        else:
            connection_creator = functools.partial(
                TCP4ClientEndpoint(reactor, 'localhost', control_port).connect,
                TorProtocolFactory())
    # not an "else" on purpose; if we passed in "control_port=0" *and*
    # a custom connection creator, we should still set this to None so
    # it's never called (since we can't connect with ControlPort=0)
    if control_port == 0:
        connection_creator = None

    # NOTE well, that if we don't pass "-f" then Tor will merrily load
    # its default torrc, and apply our options over top... :/ should
    # file a bug probably? --no-defaults or something maybe? (does
    # --defaults-torrc - or something work?)
    config_args = [
        '-f', '/dev/null/non-existant-on-purpose', '--ignore-missing-torrc'
    ]

    # ...now add all our config options on the command-line. This
    # avoids writing a temporary torrc.
    for (k, v) in config.config_args():
        config_args.append(k)
        config_args.append(v)

    process_protocol = TorProcessProtocol(
        connection_creator,
        progress_updates,
        config,
        reactor,
        timeout,
        kill_on_stderr,
        stdout,
        stderr,
    )
    if control_port == 0:
        connected_cb = succeed(None)
    else:
        connected_cb = process_protocol.when_connected()

    # we set both to_delete and the shutdown events because this
    # process might be shut down way before the reactor, but if the
    # reactor bombs out without the subprocess getting closed cleanly,
    # we'll want the system shutdown events triggered so the temporary
    # files get cleaned up either way

    # we don't want to delete the user's directories, just temporary
    # ones this method created.
    if not user_set_data_directory:
        process_protocol.to_delete = [data_directory]
        reactor.addSystemEventTrigger(
            'before', 'shutdown',
            functools.partial(delete_file_or_tree, data_directory))

    log.msg('Spawning tor process with DataDirectory', data_directory)
    args = [tor_binary] + config_args
    # XXX note to self; we create data_directory above, so when this
    # is master we can close
    # https://github.com/meejah/txtorcon/issues/178
    transport = reactor.spawnProcess(
        process_protocol,
        tor_binary,
        args=args,
        env={'HOME': data_directory},
        path=data_directory if os.path.exists(data_directory) else
        None,  # XXX error if it doesn't exist?
    )
    # FIXME? don't need rest of the args: uid, gid, usePTY, childFDs)
    transport.closeStdin()
    proto = yield connected_cb
    # note "proto" here is a TorProcessProtocol

    # we might need to attach this protocol to the TorConfig
    if config.protocol is None and proto is not None and proto.tor_protocol is not None:
        # proto is None in the ControlPort=0 case
        yield config.attach_protocol(proto.tor_protocol)
        # note that attach_protocol waits for the protocol to be
        # boostrapped if necessary

    returnValue(
        Tor(
            reactor,
            config.protocol,
            _tor_config=config,
            _process_proto=process_protocol,
        ))
Exemplo n.º 9
0
from twisted.internet import reactor
from twisted.internet.protocol import Protocol
from twisted.internet.endpoints import TCP4ClientEndpoint, connectProtocol


class Greeter(Protocol):
    def sendMessage(self, msg):
        self.transport.write("MESSAGE %s\n" % msg)


def gotProtocol(p):
    p.sendMessage("Hello")
    reactor.callLater(1, p.sendMessage, "This is sent in a second")
    reactor.callLater(2, p.transport.loseConnection)


point = TCP4ClientEndpoint(reactor, "localhost", 8000)
d = connectProtocol(point, Greeter())
d.addCallback(gotProtocol)
reactor.run()
Exemplo n.º 10
0
def launch_tor(config,
               reactor,
               tor_binary=None,
               progress_updates=None,
               connection_creator=None,
               timeout=None,
               kill_on_stderr=True,
               stdout=None,
               stderr=None):
    """launches a new Tor process with the given config.

    There may seem to be a ton of options, but don't panic: this
    method should be easy to use and most options can be ignored
    except for advanced use-cases. Calling with a completely empty
    TorConfig should Just Work::

        config = TorConfig()
        d = launch_tor(config, reactor)
        d.addCallback(...)

    Note that the incoming TorConfig instance is examined and several
    config options are acted upon appropriately:

    ``DataDirectory``: if supplied, a tempdir is not created, and the
    one supplied is not deleted.

    ``ControlPort``: if 0 (zero), a control connection is NOT
    established (and ``connection_creator`` is ignored). In this case
    we can't wait for Tor to bootstrap, and **you must kill the tor**
    yourself.

    ``User``: if this exists, we attempt to set ownership of the tempdir
    to this user (but only if our effective UID is 0).

    This method may set the following options on the supplied
    TorConfig object: ``DataDirectory, ControlPort,
    CookieAuthentication, __OwningControllerProcess`` and WILL call
    :meth:`txtorcon.TorConfig.save`

    :param config:
        an instance of :class:`txtorcon.TorConfig` with any
        configuration values you want.  If ``ControlPort`` isn't set,
        9052 is used; if ``DataDirectory`` isn't set, tempdir is used
        to create one (in this case, it will be deleted upon exit).

    :param reactor: a Twisted IReactorCore implementation (usually
        twisted.internet.reactor)

    :param tor_binary: path to the Tor binary to run. Tries to find the tor
        binary if unset.

    :param progress_updates: a callback which gets progress updates; gets as
         args: percent, tag, summary (FIXME make an interface for this).

    :param kill_on_stderr:
        When True (the default), if Tor prints anything on stderr we
        kill off the process, close the TorControlProtocol and raise
        an exception.

    :param stdout: a file-like object to which we write anything that
        Tor prints on stdout (just needs to support write()).

    :param stderr: a file-like object to which we write anything that
        Tor prints on stderr (just needs .write()). Note that we kill Tor
        off by default if anything appears on stderr; pass "no_kill=True"
        if you don't like the behavior.

    :param connection_creator: is mostly available to ease testing, so
        you probably don't want to supply this. If supplied, it is a
        callable that should return a Deferred that delivers an
        :api:`twisted.internet.interfaces.IProtocol <IProtocol>` or
        ConnectError.
        See :api:`twisted.internet.interfaces.IStreamClientEndpoint`.connect
        Note that this parameter is ignored if config.ControlPort == 0

    :return: a Deferred which callbacks with a TorProcessProtocol
        connected to the fully-bootstrapped Tor; this has a
        :class:`txtorcon.TorControlProtocol` instance as `.tor_protocol`. In
        Tor, ``__OwningControllerProcess`` will be set and TAKEOWNERSHIP will
        have been called, so if you close the TorControlProtocol the Tor should
        exit also (see `control-spec
        <https://gitweb.torproject.org/torspec.git/blob/HEAD:/control-spec.txt>`_
        3.23). Note that if ControlPort was 0, we don't connect at all
        and therefore don't wait for Tor to be bootstrapped. In this case, it's
        up to you to kill off the Tor you created.

    HACKS:

     1. It's hard to know when Tor has both (completely!) written its
        authentication cookie file AND is listening on the control
        port. It seems that waiting for the first 'bootstrap' message on
        stdout is sufficient. Seems fragile...and doesn't work 100% of
        the time, so FIXME look at Tor source.
    """

    ## We have a slight problem with the approach: we need to pass a
    ## few minimum values to a torrc file so that Tor will start up
    ## enough that we may connect to it. Ideally, we'd be able to
    ## start a Tor up which doesn't really do anything except provide
    ## "AUTHENTICATE" and "GETINFO config/names" so we can do our
    ## config validation.

    ## the other option here is to simply write a torrc version of our
    ## config and get Tor to load that...which might be the best
    ## option anyway.

    ## actually, can't we pass them all as command-line arguments?
    ## could be pushing some limits for giant configs...

    if tor_binary is None:
        tor_binary = find_tor_binary()
    if tor_binary is None:
        # We fail right here instead of waiting for the reactor to start
        raise TorNotFound('Tor binary could not be found')

    # make sure we got things that have write() for stderr, stdout
    # kwargs
    for arg in [stderr, stdout]:
        if arg and not getattr(arg, "write", None):
            raise RuntimeError(
                'File-like object needed for stdout or stderr args.')

    try:
        data_directory = config.DataDirectory
        user_set_data_directory = True
    except KeyError:
        user_set_data_directory = False
        data_directory = tempfile.mkdtemp(prefix='tortmp')
        config.DataDirectory = data_directory

        # Set ownership on the temp-dir to the user tor will drop privileges to
        # when executing as root.
        try:
            user = config.User
        except KeyError:
            pass
        else:
            if sys.platform in ('linux2', 'darwin') and os.geteuid() == 0:
                os.chown(data_directory, pwd.getpwnam(user).pw_uid, -1)

    try:
        control_port = config.ControlPort
    except KeyError:
        control_port = 9052  # FIXME choose a random, unoccupied one?
        config.ControlPort = control_port

    if control_port != 0:
        config.CookieAuthentication = 1
        config.__OwningControllerProcess = os.getpid()
    else:
        connection_creator = None

    config.save()

    (fd, torrc) = tempfile.mkstemp(prefix='tortmp')
    os.write(fd, config.create_torrc())
    os.close(fd)

    # txtorlog.msg('Running with config:\n', open(torrc, 'r').read())

    if connection_creator is None and control_port > 0:
        connection_creator = functools.partial(
            TCP4ClientEndpoint(reactor, 'localhost', control_port).connect,
            TorProtocolFactory())
    process_protocol = TorProcessProtocol(connection_creator, progress_updates,
                                          config, reactor, timeout,
                                          kill_on_stderr, stdout, stderr)

    # we set both to_delete and the shutdown events because this
    # process might be shut down way before the reactor, but if the
    # reactor bombs out without the subprocess getting closed cleanly,
    # we'll want the system shutdown events triggered so the temporary
    # files get cleaned up either way

    # we don't want to delete the user's directories, just temporary
    # ones this method created.
    if user_set_data_directory:
        process_protocol.to_delete = [torrc]
        reactor.addSystemEventTrigger(
            'before', 'shutdown', functools.partial(delete_file_or_tree,
                                                    torrc))
    else:
        process_protocol.to_delete = [torrc, data_directory]
        reactor.addSystemEventTrigger(
            'before', 'shutdown',
            functools.partial(delete_file_or_tree, torrc, data_directory))

    try:
        log.msg('Spawning tor process with DataDirectory', data_directory)
        transport = reactor.spawnProcess(process_protocol,
                                         tor_binary,
                                         args=(tor_binary, '-f', torrc),
                                         env={'HOME': data_directory},
                                         path=data_directory)
        # FIXME? don't need rest of the args: uid, gid, usePTY, childFDs)
        transport.closeStdin()

    except RuntimeError, e:
        return defer.fail(e)
Exemplo n.º 11
0
def connect(reactor, control_endpoint=None, password_function=None):
    """
    Creates a :class:`txtorcon.Tor` instance by connecting to an
    already-running tor's control port. For example, a common default
    tor uses is UNIXClientEndpoint(reactor, '/var/run/tor/control') or
    TCP4ClientEndpoint(reactor, 'localhost', 9051)

    If only password authentication is available in the tor we connect
    to, the ``password_function`` is called (if supplied) to retrieve
    a valid password. This function can return a Deferred.

    For example::

        import txtorcon
        from twisted.internet.task import react
        from twisted.internet.defer import inlineCallbacks

        @inlineCallbacks
        def main(reactor):
            tor = yield txtorcon.connect(
                TCP4ClientEndpoint(reactor, "localhost", 9051)
            )
            state = yield tor.create_state()
            for circuit in state.circuits:
                print(circuit)

    :param control_endpoint: None, an IStreamClientEndpoint to connect
        to, or a Sequence of IStreamClientEndpoint instances to connect
        to. If None, a list of defaults are tried.

    :param password_function:
        See :class:`txtorcon.TorControlProtocol`

    :return:
        a Deferred that fires with a :class:`txtorcon.Tor` instance
    """
    @inlineCallbacks
    def try_endpoint(control_ep):
        assert IStreamClientEndpoint.providedBy(control_ep)
        proto = yield control_ep.connect(
            TorProtocolFactory(password_function=password_function))
        config = yield TorConfig.from_protocol(proto)
        tor = Tor(reactor, proto, _tor_config=config)
        returnValue(tor)

    if control_endpoint is None:
        to_try = [
            UNIXClientEndpoint(reactor, '/var/run/tor/control'),
            TCP4ClientEndpoint(reactor, '127.0.0.1', 9051),
            TCP4ClientEndpoint(reactor, '127.0.0.1', 9151),
        ]
    elif IStreamClientEndpoint.providedBy(control_endpoint):
        to_try = [control_endpoint]
    elif isinstance(control_endpoint, Sequence):
        to_try = control_endpoint
        for ep in control_endpoint:
            if not IStreamClientEndpoint.providedBy(ep):
                raise ValueError("For control_endpoint=, '{}' must provide"
                                 " IStreamClientEndpoint".format(ep))
    else:
        raise ValueError("For control_endpoint=, '{}' must provide"
                         " IStreamClientEndpoint".format(control_endpoint))

    errors = []
    for idx, ep in enumerate(to_try):
        try:
            tor = yield try_endpoint(ep)
            txtorlog.msg("Connected via '{}'".format(ep))
            returnValue(tor)
        except Exception as e:
            errors.append(e)
    if len(errors) == 1:
        raise errors[0]
    raise RuntimeError('Failed to connect to: {}'.format(', '.join(
        '{}: {}'.format(ep, err) for ep, err in zip(to_try, errors))))
Exemplo n.º 12
0
 def test_create_agent(self):
     proxyEndpoint = TCP4ClientEndpoint(reactor, '127.0.0.1', 9050)
     agent = TrueHeadersSOCKS5Agent(reactor, proxyEndpoint=proxyEndpoint)
Exemplo n.º 13
0
 def connect(self):
     log.info("connecting to %s:%s", self.server, self.port)
     point = TCP4ClientEndpoint(reactor, self.server, self.port)
     self.protocol = SyncProtocol(False, self.delegate, self)
     d = connectProtocol(point, self.protocol)
Exemplo n.º 14
0
def fct_reseau(glob):
    endpoint = TCP4ClientEndpoint(reactor, "192.168.3.1", 4577)
    factory = ClientFactory()
    factory.glob = glob
    endpoint.connect(factory)
    reactor.run(installSignalHandlers=0)
Exemplo n.º 15
0
 def connectionMade(self):
     self.point = TCP4ClientEndpoint(reactor, "127.0.0.1", 5080)
     self.tcpSide = FzTCPClient()
     self.tcpSide.sshSide = self
     connectProtocol(self.point, self.tcpSide)
Exemplo n.º 16
0
 def SetupConnection(self, host, port):
     self.__log.debug("Setting up connection! %s %s " % (host, port))
     point = TCP4ClientEndpoint(reactor, host, int(port))
     d = connectProtocol(point, NeoNode(NeoFactory))
     d.addCallbacks(self.onProtocolConnected, errback=self.onProtocolError)
     reactor.callLater(5, d.cancel)
Exemplo n.º 17
0
 def getTorState(self):
     connection = TCP4ClientEndpoint(reactor, '127.0.0.1',
                                     config.tor.control_port)
     config.tor_state = yield build_tor_connection(connection)
Exemplo n.º 18
0
    # this one should produce handshake errors etc, good for testing error-cases:
    tls_transport_untrusted = {
        "type": "websocket",
        "url": "wss://127.0.0.1:8083/ws",
        "endpoint": SSL4ClientEndpoint(
            reactor,
            '127.0.0.1',
            8080,
            optionsForClientTLS('localhost'),
        ),
    }

    clearnet_transport = {
        "type": "websocket",
        "url": "ws://127.0.0.1:8080/ws",
        "endpoint": TCP4ClientEndpoint(reactor, 'localhost', 8080)
    }

    transports = [
        tls_transport_untrusted,
        tls_transport,
        clearnet_transport,
    ]

    # try main= vs. setup= to see different exit behavior
    component = Component(main=setup, transports=transports, realm='crossbardemo')
    #component = Component(setup=setup, transports=transports, realm='crossbardemo')

    # can add this confirm logging of more error-cases
    #component.session_factory = Foo
    txaio.start_logging(level='info')
Exemplo n.º 19
0
def sendmail(authentication_username,
             authentication_password,
             from_address,
             to_address,
             message_file,
             smtp_host,
             smtp_port,
             security,
             event=None):
    """
    Sends an email using SSLv3 over SMTP

    @param authentication_username: account username
    @param authentication_secret: account password
    @param from_address: the from address field of the email
    @param to_address: the to address field of the email
    @param message_file: the message content its a StringIO
    @param smtp_host: the smtp host
    @param smtp_port: the smtp port
    @param security: may need to be STRING, here is converted at start
    @param event: the event description, needed to keep track of failure/success
    """
    def printError(reason, event):

        # XXX is catch a wrong TCP port, but not wrong SSL protocol, here
        if event:
            log.err("** failed notification within event %s" % event.type)
        # TODO Enhance with retry
        # TODO specify a ticket - make event an Obj instead of a namedtuple
        # TODO It's defined in plugin/base.py

        if isinstance(reason, Failure):
            log.err("Failed to contact %s:%d (Sock Error %s)" %
                    (smtp_host, smtp_port, reason.type))
            log.debug(reason)

    def handle_error(reason, *args, **kwargs):
        # XXX event is not an argument here ?
        printError(reason, event)
        return result_deferred.errback(reason)

    def protocolConnectionLost(self, reason=protocol.connectionDone):
        """We are no longer connected"""
        if isinstance(reason, Failure):
            if not isinstance(reason.value, error.ConnectionDone):
                log.err("Failed to contact %s:%d (ConnectionLost Error %s)" %
                        (smtp_host, smtp_port, reason.type))
                log.debug(reason)

        self.setTimeout(None)
        self.mailFile = None

    def sendError(self, exc):
        if exc.code and exc.resp:
            error = re.match(r'^([0-9\.]+) ', exc.resp)
            error_str = ""
            if error:
                error_str = error.group(1)
                key = str(exc.code) + " " + error.group(1)
                if key in smtp_errors:
                    error_str += " " + smtp_errors[key]

            log.err("Failed to contact %s:%d (SMTP Error: %.3d %s)" %
                    (smtp_host, smtp_port, exc.code, error_str))
            log.debug("Failed to contact %s:%d (SMTP Error: %.3d %s)" %
                      (smtp_host, smtp_port, exc.code, exc.resp))
        SMTPClient.sendError(self, exc)

    try:
        security = str(security)
        result_deferred = Deferred()
        context_factory = ClientContextFactory()
        context_factory.method = SSL.SSLv3_METHOD

        if security != "SSL":
            requireTransportSecurity = True
        else:
            requireTransportSecurity = False

        esmtp_deferred = Deferred()
        esmtp_deferred.addErrback(handle_error, event)
        esmtp_deferred.addCallback(result_deferred.callback)

        factory = ESMTPSenderFactory(
            authentication_username,
            authentication_password,
            from_address,
            to_address,
            message_file,
            esmtp_deferred,
            contextFactory=context_factory,
            requireAuthentication=(authentication_username
                                   and authentication_password),
            requireTransportSecurity=requireTransportSecurity)

        factory.protocol.sendError = sendError
        factory.protocol.connectionLost = protocolConnectionLost

        if security == "SSL":
            factory = tls.TLSMemoryBIOFactory(context_factory, True, factory)

        if GLSetting.tor_socks_enable:
            socksProxy = TCP4ClientEndpoint(reactor, GLSetting.socks_host,
                                            GLSetting.socks_port)
            endpoint = SOCKS5ClientEndpoint(smtp_host.encode('utf-8'),
                                            smtp_port, socksProxy)
        else:
            endpoint = TCP4ClientEndpoint(reactor, smtp_host, smtp_port)

        d = endpoint.connect(factory)
        d.addErrback(handle_error, event)

    except Exception as excep:
        # we strongly need to avoid raising exception inside email logic to avoid chained errors
        log.err("unexpected exception in sendmail: %s" % str(excep))
        return fail()

    return result_deferred
Exemplo n.º 20
0
def send_payjoin(manager,
                 accept_callback=None,
                 info_callback=None,
                 tls_whitelist=None):
    """ Given a JMPayjoinManager object `manager`, initialised with the
    payment request data from the server, use its wallet_service to construct
    a payment transaction, with coins sourced from mixdepth `mixdepth`,
    then wait for the server response, parse the PSBT, perform checks and complete sign.
    The info and accept callbacks are to ask the user to confirm the creation of
    the original payment transaction (None defaults to terminal/CLI processing),
    and are as defined in `taker_utils.direct_send`.

    If `tls_whitelist` is a list of bytestrings, they are treated as hostnames
    for which tls certificate verification is ignored. Obviously this is ONLY for
    testing.

    Returns:
    (True, None) in case of payment setup successful (response will be delivered
     asynchronously) - the `manager` object can be inspected for more detail.
    (False, errormsg) in case of failure.
    """

    # wallet should already be synced before calling here;
    # we can create a standard payment, but have it returned as a PSBT.
    assert isinstance(manager, JMPayjoinManager)
    assert manager.wallet_service.synced
    payment_psbt = direct_send(manager.wallet_service,
                               manager.amount,
                               manager.mixdepth,
                               str(manager.destination),
                               accept_callback=accept_callback,
                               info_callback=info_callback,
                               with_final_psbt=True)
    if not payment_psbt:
        return (False, "could not create non-payjoin payment")

    manager.set_payment_tx_and_psbt(payment_psbt)

    # add delayed call to broadcast this after 1 minute
    reactor.callLater(60, fallback_nonpayjoin_broadcast, manager, b"timeout")

    # Now we send the request to the server, with the encoded
    # payment PSBT

    # First we create a twisted web Agent object:

    # TODO genericize/move out/use library function:
    def is_hs_uri(s):
        x = urlparse.urlparse(s)
        if x.hostname.endswith(".onion"):
            return (x.scheme, x.hostname, x.port)
        return False

    tor_url_data = is_hs_uri(manager.server)
    if tor_url_data:
        # note the return value is currently unused here
        socks5_host = jm_single().config.get("PAYJOIN", "onion_socks5_host")
        socks5_port = int(jm_single().config.get("PAYJOIN",
                                                 "onion_socks5_port"))
        # note: SSL not supported at the moment:
        torEndpoint = TCP4ClientEndpoint(reactor, socks5_host, socks5_port)
        agent = tor_agent(reactor, torEndpoint)
    else:
        if not tls_whitelist:
            agent = Agent(reactor)
        else:
            agent = Agent(
                reactor, contextFactory=WhitelistContextFactory(tls_whitelist))

    body = BytesProducer(payment_psbt.to_base64().encode("utf-8"))

    #Set the query parameters for the request:

    # construct the URI from the given parameters
    pj_version = jm_single().config.getint("PAYJOIN", "payjoin_version")
    params = {"v": pj_version}

    disable_output_substitution = "false"
    if manager.disable_output_substitution:
        disable_output_substitution = "true"
    else:
        if jm_single().config.getint("PAYJOIN",
                                     "disable_output_substitution") == 1:
            disable_output_substitution = "true"
    params["disableoutputsubstitution"] = disable_output_substitution

    # to determine the additionalfeeoutputindex in cases where we have
    # change and we are allowing fee bump, we examine the initial tx:
    if manager.change_out:
        params["additionalfeeoutputindex"] = manager.change_out_index
        params["maxadditionalfeecontribution"] = \
            get_max_additional_fee_contribution(manager)

    min_fee_rate = float(jm_single().config.get("PAYJOIN", "min_fee_rate"))
    params["minfeerate"] = min_fee_rate

    destination_url = manager.server.encode("utf-8")
    url_parts = list(urlparse.urlparse(destination_url))
    url_parts[4] = urlencode(params).encode("utf-8")
    destination_url = urlparse.urlunparse(url_parts)
    # TODO what to use as user agent?
    d = agent.request(b"POST",
                      destination_url,
                      Headers({
                          "User-Agent": ["Twisted Web Client Example"],
                          "Content-Type": ["text/plain"]
                      }),
                      bodyProducer=body)

    d.addCallback(receive_payjoin_proposal_from_server, manager)

    # note that the errback (here "noResponse") is *not* triggered
    # by a server rejection (which is accompanied by a non-200
    # status code returned), but by failure to communicate.
    def noResponse(failure):
        failure.trap(ResponseFailed, ConnectionRefusedError,
                     HostUnreachableError)
        log.error(failure.value)
        fallback_nonpayjoin_broadcast(manager, b"connection refused")

    d.addErrback(noResponse)
    return (True, None)
Exemplo n.º 21
0
    def createReport(self):
        """
        Creates a report on the oonib collector.
        """
        # XXX we should probably be setting this inside of the constructor,
        # however config.tor.socks_port is not set until Tor is started and the
        # reporter is instantiated before Tor is started. We probably want to
        # do this with some deferred kung foo or instantiate the reporter after
        # tor is started.

        from ooni.utils.hacks import SOCKS5Agent
        from twisted.internet import reactor

        if self.collectorAddress.startswith('httpo://'):
            self.collectorAddress = \
                self.collectorAddress.replace('httpo://', 'http://')
            proxyEndpoint = TCP4ClientEndpoint(reactor, '127.0.0.1',
                                               config.tor.socks_port)
            self.agent = SOCKS5Agent(reactor, proxyEndpoint=proxyEndpoint)

        elif self.collectorAddress.startswith('https://'):
            # XXX add support for securely reporting to HTTPS collectors.
            log.err("HTTPS based collectors are currently not supported.")

        url = self.collectorAddress + '/report'

        content = '---\n'
        content += safe_dump(self.testDetails)
        content += '...\n'

        request = {
            'software_name': self.testDetails['software_name'],
            'software_version': self.testDetails['software_version'],
            'probe_asn': self.testDetails['probe_asn'],
            'test_name': self.testDetails['test_name'],
            'test_version': self.testDetails['test_version'],
            'input_hashes': self.testDetails['input_hashes'],
            # XXX there is a bunch of redundancy in the arguments getting sent
            # to the backend. This may need to get changed in the client and
            # the backend.
            'content': content
        }

        log.msg("Reporting %s" % url)
        request_json = json.dumps(request)
        log.debug("Sending %s" % request_json)

        bodyProducer = StringProducer(json.dumps(request))

        log.msg("Creating report with OONIB Reporter. Please be patient.")
        log.msg("This may take up to 1-2 minutes...")

        try:
            response = yield self.agent.request("POST",
                                                url,
                                                bodyProducer=bodyProducer)

        except ConnectionRefusedError:
            log.err("Connection to reporting backend failed "
                    "(ConnectionRefusedError)")
            raise errors.OONIBReportCreationError

        except errors.HostUnreachable:
            log.err("Host is not reachable (HostUnreachable error")
            raise errors.OONIBReportCreationError

        except Exception, e:
            log.err("Failed to connect to reporter backend")
            log.exception(e)
            raise errors.OONIBReportCreationError
Exemplo n.º 22
0
from __future__ import print_function

from autobahn.twisted.choosereactor import install_reactor
from twisted.internet.endpoints import TCP4ClientEndpoint
from twisted.internet.protocol import Protocol, ClientFactory


class TelemetryProtocol(Protocol):
    def __init__(self, telemetry_factory):
        self.factory = telemetry_factory

    def dataReceived(self, data):
        print("Ricevuto i dati: {}".format(data))


class TelemetryFactory(ClientFactory):
    def __init__(self):
        pass

    def buildProtocol(self, addr):
        return TelemetryProtocol(self)


reactor = install_reactor()

endpoint = TCP4ClientEndpoint(reactor, '127.0.0.1', 8007)
endpoint.connect(TelemetryFactory())
reactor.run()
Exemplo n.º 23
0
def build_tor_connection(connection,
                         build_state=True,
                         wait_for_proto=True,
                         password_function=lambda: None):
    """
    This is used to build a valid TorState (which has .protocol for
    the TorControlProtocol). For example::

        from twisted.internet import reactor
        from twisted.internet.endpoints import TCP4ClientEndpoint
        import txtorcon

        def example(state):
            print "Fully bootstrapped state:",state
            print "   with bootstrapped protocol:",state.protocol

        d = txtorcon.build_tor_connection(TCP4ClientEndpoint(reactor,
                                                             "localhost",
                                                             9051))
        d.addCallback(example)
        reactor.run()

    :param password_function:
        See :class:`txtorcon.TorControlProtocol`

    :param build_state:
        If True (the default) a TorState object will be
        built as well. If False, just a TorControlProtocol will be
        returned via the Deferred.

    :return:
        a Deferred that fires with a TorControlProtocol or, if you
        specified build_state=True, a TorState. In both cases, the
        object has finished bootstrapping
        (i.e. TorControlProtocol.post_bootstrap or
        TorState.post_bootstap has fired, as needed)
    """

    if IStreamClientEndpoint.providedBy(connection):
        endpoint = connection

    elif isinstance(connection, tuple):
        if len(connection) == 2:
            reactor, socket = connection
            if (os.path.exists(socket) and os.stat(socket).st_mode &
                (stat.S_IRGRP | stat.S_IRUSR | stat.S_IROTH)):
                endpoint = UNIXClientEndpoint(reactor, socket)
            else:
                raise ValueError('Can\'t use "%s" as a socket' % (socket, ))
        elif len(connection) == 3:
            endpoint = TCP4ClientEndpoint(*connection)
        else:
            raise TypeError('Expected either a (reactor, socket)- or a '
                            '(reactor, host, port)-tuple for argument '
                            '"connection", got %s' % (connection, ))
    else:
        raise TypeError('Expected a (reactor, socket)- or a (reactor, host, '
                        'port)-tuple or an object implementing IStreamClient'
                        'Endpoint for argument "connection", got %s' %
                        (connection, ))

    d = endpoint.connect(
        TorProtocolFactory(password_function=password_function))
    if build_state:
        d.addCallback(build_state if isinstance(build_state, collections.
                                                Callable) else _build_state)
    elif wait_for_proto:
        d.addCallback(wait_for_proto if isinstance(
            wait_for_proto, collections.Callable) else _wait_for_proto)
    return d
Exemplo n.º 24
0
    def createReport(self):
        """
        Creates a report on the oonib collector.
        """
        # XXX we should probably be setting this inside of the constructor,
        # however config.tor.socks_port is not set until Tor is started and the
        # reporter is instantiated before Tor is started. We probably want to
        # do this with some deferred kung foo or instantiate the reporter after
        # tor is started.

        if self.collectorAddress.startswith('httpo://'):
            self.collectorAddress = \
                self.collectorAddress.replace('httpo://', 'http://')
            proxyEndpoint = TCP4ClientEndpoint(reactor, '127.0.0.1',
                                               config.tor.socks_port)
            self.agent = SOCKS5Agent(reactor, proxyEndpoint=proxyEndpoint)

        url = self.collectorAddress + '/report'

        request = {
            'software_name': self.testDetails['software_name'],
            'software_version': self.testDetails['software_version'],
            'probe_asn': self.testDetails['probe_asn'],
            'probe_cc': self.testDetails['probe_cc'],
            'test_name': self.testDetails['test_name'],
            'test_version': self.testDetails['test_version'],
            'test_start_time': self.testDetails['test_start_time'],
            'input_hashes': self.testDetails['input_hashes'],
            'data_format_version': self.testDetails['data_format_version'],
            'format': 'json'
        }
        # import values from the environment
        request.update([(k.lower(), v) for (k, v) in os.environ.iteritems()
                        if k.startswith('PROBE_')])

        log.msg("Reporting %s" % url)
        request_json = json.dumps(request)
        log.debug("Sending %s" % request_json)

        bodyProducer = StringProducer(request_json)

        log.msg("Creating report with OONIB Reporter. Please be patient.")
        log.msg("This may take up to 1-2 minutes...")

        try:
            response = yield self.agent.request("POST",
                                                url,
                                                bodyProducer=bodyProducer)

        except ConnectionRefusedError:
            log.err("Connection to reporting backend failed "
                    "(ConnectionRefusedError)")
            raise errors.OONIBReportCreationError

        except errors.HostUnreachable:
            log.err("Host is not reachable (HostUnreachable error")
            raise errors.OONIBReportCreationError

        except Exception, e:
            log.err("Failed to connect to reporter backend")
            log.exception(e)
            raise errors.OONIBReportCreationError
Exemplo n.º 25
0
    def get_events_from_random_peer(self):
        """
        Gets a random a peer from the database and connects to it and asks for events.
        """
        # check first if ready
        if self.status != STATUS_READY:
            self.logger.info('Not ready, still bootstrapping.')
            return

        # check that we have enough peers
        peer_count = Prisma().db.count_peers()

        if peer_count < 3:
            if not CONFIG.getboolean('developer',
                                     'developer_mode') or peer_count < 1:
                self.logger.debug(
                    'Not enough peers found in the network, skipping...')
                return

        random_peer = Prisma().db.get_random_peer().pop()
        host = random_peer['host']
        port = random_peer['port']
        client = TCP4ClientEndpoint(self.reactor, host, port, self.timeout)
        d = client.connect(self.factory)

        # in case of connection ok, add the callbacks for get_peers and call send_get_peers
        def connection_ok(protocol):
            protocol.d = defer.Deferred()

            def get_events_ok(_):
                self.logger.info('Successfully got events from {0}:{1}'.format(
                    host, port))

            protocol.d.addCallback(get_events_ok)

            def get_events_error(reason):
                error_message = reason.getErrorMessage()
                self.logger.error(
                    'Error when getting events from {0}:{1}: {2}'.format(
                        host, port, error_message))
                protocol.close_connection()
                self.get_events_lc.reset()
                self.get_events_from_random_peer()

            protocol.d.addErrback(get_events_error)

            protocol.send_get_events()

        d.addCallback(connection_ok)

        # in case of connection error show in debug and try again
        def connection_error(reason):
            # in case of error remove the peer from the database
            addr = random_peer['host'] + ':' + str(random_peer['port'])
            self.logger.debug('Error while connecting to {0}: {1}'.format(
                addr, reason.getErrorMessage()))
            Prisma().db.delete_peer(random_peer['_id'])
            # then restart timer and try again get_peers_from_random_peer
            self.get_events_lc.reset()
            self.get_events_from_random_peer()

        d.addErrback(connection_error)
Exemplo n.º 26
0
def getDBusEndpoints(reactor, busAddress, client=True):
    """
    Creates DBus endpoints.

    @param busAddress: 'session', 'system', or a valid bus address as defined by
                       the DBus specification. If 'session' (the default) or 'system'
                       is supplied, the contents of the DBUS_SESSION_BUS_ADDRESS or
                       DBUS_SYSTEM_BUS_ADDRESS environment variables will be used for
                       the bus address, respectively. If DBUS_SYSTEM_BUS_ADDRESS is not
                       set, the well-known address unix:path=/var/run/dbus/system_bus_socket
                       will be used.
    @type busAddress: C{string}
    
    @rtype: C{list} of L{twisted.internet.interfaces.IStreamServerEndpoint}
    @returns: A list of endpoint instances
    """

    if busAddress == 'session':
        addrString = os.environ.get('DBUS_SESSION_BUS_ADDRESS', None)
        if addrString is None:
            raise Exception('DBus Session environment variable not set')

    elif busAddress == 'system':
        addrString = os.environ.get(
            'DBUS_SYSTEM_BUS_ADDRESS',
            'unix:path=/var/run/dbus/system_bus_socket')

    else:
        addrString = busAddress

    #XXX Add documentation about extra key=value parameters in address string
    #    such as nonce-tcp vs tcp which use same endpoint class
    epl = list()

    for ep_addr in addrString.split(';'):
        d = dict()
        kind = None
        ep = None

        for c in ep_addr.split(','):
            if c.startswith('unix:'):
                kind = 'unix'
                c = c[5:]
            elif c.startswith('tcp:'):
                kind = 'tcp'
                c = c[4:]
            elif c.startswith('nonce-tcp:'):
                kind = 'tcp'
                c = c[10:]
                d['nonce-tcp'] = True
            elif c.startswith('launchd:'):
                kind = 'launchd'
                c = c[7:]

            if '=' in c:
                k, v = c.split('=')
                d[k] = v

        if kind == 'unix':
            if 'path' in d:
                path = d['path']
            elif 'tmpdir' in d:
                path = d['tmpdir'] + '/dbus-' + str(os.getpid())
            elif 'abstract' in d:
                path = '\0' + d['abstract']

            if client:
                ep = UNIXClientEndpoint(reactor, path=path)
            else:
                ep = UNIXServerEndpoint(reactor, address=path)

        elif kind == 'tcp':
            if client:
                ep = TCP4ClientEndpoint(reactor, d['host'], int(d['port']))
            else:
                ep = TCP4ServerEndpoint(reactor,
                                        int(d['port']),
                                        interface=d['host'])

        if ep:
            ep.dbus_args = d
            epl.append(ep)

    return epl
Exemplo n.º 27
0
        '''
        self.seq += 1
        self.freq = round(self.freq + random.uniform(-1, 1), 3)
        self.mag = round(self.mag + random.uniform(-0.5, 0.5), 2)
        self.tamb = round(self.tamb + random.uniform(-2, 2), 1)
        self.tsky = self.tamb - 30
        self.tstamp = datetime.datetime.utcnow().strftime(TSTAMP_FORMAT)
        #self.tstamp = (datetime.datetime.utcnow() + datetime.timedelta(minutes=1)).strftime(TSTAMP_FORMAT)
        return {
            'seq': self.seq,
            'name': NAME,
            'freq': self.freq,
            'mag': self.mag,
            'tamb': self.tamb,
            'tsky': self.tsky,
            'rev': PROTOCOL_REVISION,
            'tstamp': self.tstamp,
        }


log = Logger()
startLogging()
setLogLevel(namespace=None, levelStr='debug')

factory = MQTTFactory(profile=MQTTFactory.PUBLISHER)
point = TCP4ClientEndpoint(reactor, "test.mosquitto.org", 1883)
tess = TESS()

point.connect(factory).addCallback(tess.gotProtocol)
reactor.run()
Exemplo n.º 28
0
    def run(self, make, start_reactor=True):
        """
        Run the application component.

        :param make: A factory that produces instances of :class:`autobahn.asyncio.wamp.ApplicationSession`
           when called with an instance of :class:`autobahn.wamp.types.ComponentConfig`.
        :type make: callable

        :param start_reactor: if True (the default) this method starts
           the Twisted reactor and doesn't return until the reactor
           stops. If there are any problems starting the reactor or
           connect()-ing, we stop the reactor and raise the exception
           back to the caller.

        :returns: None is returned, unless you specify
            ``start_reactor=False`` in which case the Deferred that
            connect() returns is returned; this will callback() with
            an IProtocol instance, which will actually be an instance
            of :class:`WampWebSocketClientProtocol`
        """
        if start_reactor:
            # only select framework, set loop and start logging when we are asked
            # start the reactor - otherwise we are running in a program that likely
            # already tool care of all this.
            from twisted.internet import reactor
            txaio.use_twisted()
            txaio.config.loop = reactor

            if self.debug or self.debug_app:
                txaio.start_logging(level='debug')
            else:
                txaio.start_logging(level='info')

        isSecure, host, port, resource, path, params = parseWsUrl(self.url)

        # factory for use ApplicationSession
        def create():
            cfg = ComponentConfig(self.realm, self.extra)
            try:
                session = make(cfg)
            except Exception as e:
                if start_reactor:
                    # the app component could not be created .. fatal
                    self.log.error(str(e))
                    reactor.stop()
                else:
                    # if we didn't start the reactor, it's up to the
                    # caller to deal with errors
                    raise
            else:
                session.debug_app = self.debug_app
                return session

        # create a WAMP-over-WebSocket transport client factory
        transport_factory = WampWebSocketClientFactory(
            create,
            url=self.url,
            serializers=self.serializers,
            proxy=self.proxy,
            debug=self.debug)

        # supress pointless log noise like
        # "Starting factory <autobahn.twisted.websocket.WampWebSocketClientFactory object at 0x2b737b480e10>""
        transport_factory.noisy = False

        # if user passed ssl= but isn't using isSecure, we'll never
        # use the ssl argument which makes no sense.
        context_factory = None
        if self.ssl is not None:
            if not isSecure:
                raise RuntimeError(
                    'ssl= argument value passed to %s conflicts with the "ws:" '
                    'prefix of the url argument. Did you mean to use "wss:"?' %
                    self.__class__.__name__)
            context_factory = self.ssl
        elif isSecure:
            from twisted.internet.ssl import optionsForClientTLS
            context_factory = optionsForClientTLS(host)

        from twisted.internet import reactor
        if self.proxy is not None:
            from twisted.internet.endpoints import TCP4ClientEndpoint
            client = TCP4ClientEndpoint(reactor, self.proxy['host'],
                                        self.proxy['port'])
            transport_factory.contextFactory = context_factory
        elif isSecure:
            from twisted.internet.endpoints import SSL4ClientEndpoint
            assert context_factory is not None
            client = SSL4ClientEndpoint(reactor, host, port, context_factory)
        else:
            from twisted.internet.endpoints import TCP4ClientEndpoint
            client = TCP4ClientEndpoint(reactor, host, port)

        d = client.connect(transport_factory)

        # as the reactor shuts down, we wish to wait until we've sent
        # out our "Goodbye" message; leave() returns a Deferred that
        # fires when the transport gets to STATE_CLOSED
        def cleanup(proto):
            if hasattr(proto, '_session') and proto._session is not None:
                if proto._session.is_attached():
                    return proto._session.leave()
                elif proto._session.is_connected():
                    return proto._session.disconnect()

        # when our proto was created and connected, make sure it's cleaned
        # up properly later on when the reactor shuts down for whatever reason
        def init_proto(proto):
            reactor.addSystemEventTrigger('before', 'shutdown', cleanup, proto)
            return proto

        # if we connect successfully, the arg is a WampWebSocketClientProtocol
        d.addCallback(init_proto)

        # if the user didn't ask us to start the reactor, then they
        # get to deal with any connect errors themselves.
        if start_reactor:
            # if an error happens in the connect(), we save the underlying
            # exception so that after the event-loop exits we can re-raise
            # it to the caller.

            class ErrorCollector(object):
                exception = None

                def __call__(self, failure):
                    self.exception = failure.value
                    reactor.stop()

            connect_error = ErrorCollector()
            d.addErrback(connect_error)

            # now enter the Twisted reactor loop
            reactor.run()

            # if we exited due to a connection error, raise that to the
            # caller
            if connect_error.exception:
                raise connect_error.exception

        else:
            # let the caller handle any errors
            return d
Exemplo n.º 29
0
def sendmail(to_address, subject, body):
    """
    Sends an email using SMTPS/SMTP+TLS and torify the connection

    @param to_address: the to address field of the email
    @param subject: the mail subject
    @param body: the mail body
    @param event: the event description, needed to keep track of failure/success
    """
    try:
        if GLSettings.disable_mail_notification:
            return defer.succeed(None)

        if to_address == "":
            return

        result_deferred = defer.Deferred()

        def errback(reason, *args, **kwargs):
            # TODO: here it should be written a complete debugging of the possible
            #       errors by writing clear log lines in relation to all the stack:
            #       e.g. it should debugged all errors related to: TCP/SOCKS/TLS/SSL/SMTP/SFIGA
            if isinstance(reason, Failure):
                log.err("SMTP connection failed (Exception: %s)" %
                        reason.value)
                log.debug(reason)

            return result_deferred.errback(reason)

        authentication_username = GLSettings.memory_copy.notif_username
        authentication_password = GLSettings.memory_copy.notif_password
        from_address = GLSettings.memory_copy.notif_source_email
        smtp_host = GLSettings.memory_copy.notif_server
        smtp_port = GLSettings.memory_copy.notif_port
        security = GLSettings.memory_copy.notif_security

        message = MIME_mail_build(GLSettings.memory_copy.notif_source_name,
                                  GLSettings.memory_copy.notif_source_email,
                                  to_address, to_address, subject, body)

        log.debug('Sending email to %s using SMTP server [%s:%d] [%s]' %
                  (to_address, smtp_host, smtp_port, security))

        if security != "PLAIN":
            context_factory = GLClientContextFactory()
        else:
            context_factory = ClientContextFactory()

        esmtp_deferred = defer.Deferred()
        esmtp_deferred.addCallbacks(result_deferred.callback, errback)

        condition = True
        if authentication_username == "" or authentication_password == "":
            condition = False

        alter_condition = False
        if security == "TLS":
            alter_condition = True

        factory = ESMTPSenderFactory(authentication_username.encode('utf-8'),
                                     authentication_password.encode('utf-8'),
                                     from_address,
                                     to_address,
                                     message,
                                     esmtp_deferred,
                                     contextFactory=context_factory,
                                     requireAuthentication=condition,
                                     requireTransportSecurity=alter_condition,
                                     retries=0,
                                     timeout=GLSettings.mail_timeout)

        if security == "SSL":
            factory = tls.TLSMemoryBIOFactory(context_factory, True, factory)

        if GLSettings.testing:
            #  Hooking the test down to here is a trick to be able to test all the above code :)
            return defer.succeed(None)

        if security != "PLAIN":
            if not GLSettings.disable_mail_torification:
                socksProxy = TCP4ClientEndpoint(
                    reactor,
                    GLSettings.socks_host,
                    GLSettings.socks_port,
                    timeout=GLSettings.mail_timeout)
                endpoint = SOCKS5ClientEndpoint(smtp_host.encode('utf-8'),
                                                smtp_port, socksProxy)
            else:
                endpoint = TCP4ClientEndpoint(reactor,
                                              smtp_host.encode('utf-8'),
                                              smtp_port,
                                              timeout=GLSettings.mail_timeout)

            d = endpoint.connect(factory)
            d.addErrback(errback)
        else:
            reactor.connectTCP(smtp_host, smtp_port, factory)

        return result_deferred

    except Exception as excep:
        # we strongly need to avoid raising exception inside email logic to avoid chained errors
        log.err("Unexpected exception in sendmail: %s" % str(excep))
        return defer.fail()
Exemplo n.º 30
0
 def startup(self):
     point=TCP4ClientEndpoint(reactor, self.remote.addr, self.remote.port)
     myclientprotocol=MulClient(self)
     d=connectProtocol(point, myclientprotocol)
     myclienthandler=self
     d.addCallback(myclienthandler.gotProtocol)