Example #1
0
    def test_create_ipaddr_fail(self, ipaddr):
        def foo(blam):
            raise ValueError('testing')

        ipaddr.ip_address.side_effect = foo
        ip = maybe_ip_addr('1.2.3.4')
        self.assertTrue(isinstance(ip, type('1.2.3.4')))
Example #2
0
    def update(self, *args):
        """
        deals with an update from Tor; see parsing logic in torcontroller
        """

        gmtexpires = None
        (name, ip, expires) = args[:3]

        for arg in args:
            if arg.lower().startswith('expires='):
                gmtexpires = arg[8:]

        if gmtexpires is None:
            if len(args) == 3:
                gmtexpires = expires
            elif len(args) > 3:
                if args[2] == 'NEVER':
                    gmtexpires = args[2]
                else:
                    gmtexpires = args[3]

        self.name = name                # "www.example.com"
        self.ip = maybe_ip_addr(ip)     # IPV4Address instance, or string

        if self.ip == '<error>':
            self._expire()
            return

        fmt = "%Y-%m-%d %H:%M:%S"

        ## if we already have expiry times, etc then we want to
        ## properly delay our timeout

        oldexpires = self.expires

        key = 'EXPIRES='
        if gmtexpires.find(key) == 0:
            gmtexpires = gmtexpires[len(key):]
        if gmtexpires == 'NEVER':
            ## FIXME can I just select a date 100 years in the future instead?
            self.expires = None
        else:
            self.expires = datetime.datetime.strptime(gmtexpires, fmt)
        self.created = datetime.datetime.utcnow()

        if self.expires is not None:
            if oldexpires is None:
                if self.expires <= self.created:
                    diff = datetime.timedelta(seconds=0)
                else:
                    diff = self.expires - self.created
                self.expiry = self.map.scheduler.callLater(diff.seconds, self._expire)

            else:
                diff = self.expires - oldexpires
                self.expiry.delay(diff.seconds)
Example #3
0
    def test_ipv6_source(self):
        listener = Listener(
            [
                ('new', {'source_addr': maybe_ip_addr('::1'),
                         'source_port': 12345})
            ]
        )

        stream = Stream(self)
        stream.listen(listener)
        stream.update("1234 NEW 0 127.0.0.1:80 SOURCE_ADDR=::1:12345 PURPOSE=USER".split())
Example #4
0
    def test_ipv6_source(self):
        listener = Listener([('new', {
            'source_addr': maybe_ip_addr('::1'),
            'source_port': 12345
        })])

        stream = Stream(self)
        stream.listen(listener)
        stream.update(
            "1234 NEW 0 127.0.0.1:80 SOURCE_ADDR=::1:12345 PURPOSE=USER".split(
            ))
Example #5
0
 def test_listener_fail(self):
     listener = Listener(
         [
             ('new', {'target_host': 'www.yahoo.com', 'target_port': 80}),
             ('attach', {'target_addr': maybe_ip_addr('1.2.3.4')}),
             ('failed', {'kwargs': dict(REASON='TIMEOUT', REMOTE_REASON='DESTROYED')})
         ]
     )
     stream = Stream(self)
     stream.listen(listener)
     stream.update("316 NEW 0 www.yahoo.com:80 SOURCE_ADDR=127.0.0.1:55877 PURPOSE=USER".split())
     self.circuits[186] = FakeCircuit(186)
     stream.update("316 REMAP 186 1.2.3.4:80 SOURCE=EXIT".split())
     stream.update("316 FAILED 0 1.2.3.4:80 REASON=TIMEOUT REMOTE_REASON=DESTROYED".split())
Example #6
0
    def test_listener_attach(self):
        self.circuits[186] = FakeCircuit(186)

        listener = Listener(
            [
                ('new', {'target_host': 'www.yahoo.com', 'target_port': 80}),
                ('attach', {'target_addr': maybe_ip_addr('1.2.3.4')})
            ]
        )

        stream = Stream(self)
        stream.listen(listener)
        stream.update("316 NEW 0 www.yahoo.com:80 SOURCE_ADDR=127.0.0.1:55877 PURPOSE=USER".split())
        stream.update("316 REMAP 186 1.2.3.4:80 SOURCE=EXIT".split())

        self.assertEqual(self.circuits[186].streams[0], stream)
Example #7
0
    def test_listener_close(self):
        self.circuits[186] = FakeCircuit(186)

        listener = Listener(
            [
                ('new', {'target_host': 'www.yahoo.com', 'target_port': 80}),
                ('attach', {'target_addr': maybe_ip_addr('1.2.3.4')}),
                ('closed', {'kwargs': dict(REASON='END', REMOTE_REASON='DONE')})
            ]
        )
        stream = Stream(self)
        stream.listen(listener)
        stream.update("316 NEW 0 www.yahoo.com:80 SOURCE_ADDR=127.0.0.1:55877 PURPOSE=USER".split())
        stream.update("316 REMAP 186 1.2.3.4:80 SOURCE=EXIT".split())
        stream.update("316 CLOSED 186 1.2.3.4:80 REASON=END REMOTE_REASON=DONE".split())

        self.assertEqual(len(self.circuits[186].streams), 0)
Example #8
0
    def test_listener_attach(self):
        self.circuits[186] = FakeCircuit(186)

        listener = Listener([('new', {
            'target_host': 'www.yahoo.com',
            'target_port': 80
        }), ('attach', {
            'target_addr': maybe_ip_addr('1.2.3.4')
        })])

        stream = Stream(self)
        stream.listen(listener)
        stream.update(
            "316 NEW 0 www.yahoo.com:80 SOURCE_ADDR=127.0.0.1:55877 PURPOSE=USER"
            .split())
        stream.update("316 REMAP 186 1.2.3.4:80 SOURCE=EXIT".split())

        self.assertEqual(self.circuits[186].streams[0], stream)
Example #9
0
    def test_listener_close(self):
        self.circuits[186] = FakeCircuit(186)

        listener = Listener([('new', {
            'target_host': 'www.yahoo.com',
            'target_port': 80
        }), ('attach', {
            'target_addr': maybe_ip_addr('1.2.3.4')
        }), ('closed', {
            'kwargs': dict(REASON='END', REMOTE_REASON='DONE')
        })])
        stream = Stream(self)
        stream.listen(listener)
        stream.update(
            "316 NEW 0 www.yahoo.com:80 SOURCE_ADDR=127.0.0.1:55877 PURPOSE=USER"
            .split())
        stream.update("316 REMAP 186 1.2.3.4:80 SOURCE=EXIT".split())
        stream.update(
            "316 CLOSED 186 1.2.3.4:80 REASON=END REMOTE_REASON=DONE".split())

        self.assertEqual(len(self.circuits[186].streams), 0)
Example #10
0
 def test_listener_fail(self):
     listener = Listener([('new', {
         'target_host': 'www.yahoo.com',
         'target_port': 80
     }), ('attach', {
         'target_addr': maybe_ip_addr('1.2.3.4')
     }),
                          ('failed', {
                              'kwargs':
                              dict(REASON='TIMEOUT',
                                   REMOTE_REASON='DESTROYED')
                          })])
     stream = Stream(self)
     stream.listen(listener)
     stream.update(
         "316 NEW 0 www.yahoo.com:80 SOURCE_ADDR=127.0.0.1:55877 PURPOSE=USER"
         .split())
     self.circuits[186] = FakeCircuit(186)
     stream.update("316 REMAP 186 1.2.3.4:80 SOURCE=EXIT".split())
     stream.update(
         "316 FAILED 0 1.2.3.4:80 REASON=TIMEOUT REMOTE_REASON=DESTROYED".
         split())
Example #11
0
    def update(self, args):
        # print "update",self.id,args

        if self.id is None:
            self.id = int(args[0])
        else:
            if self.id != int(args[0]):
                raise RuntimeError("Update for wrong stream.")

        kw = find_keywords(args)
        self.flags = kw

        if 'SOURCE_ADDR' in kw:
            last_colon = kw['SOURCE_ADDR'].rfind(':')
            self.source_addr = kw['SOURCE_ADDR'][:last_colon]
            if self.source_addr != '(Tor_internal)':
                self.source_addr = maybe_ip_addr(self.source_addr)
            self.source_port = int(kw['SOURCE_ADDR'][last_colon + 1:])

        self.state = args[1]
        # XXX why not using the state-machine stuff? ;)
        if self.state in ['NEW', 'NEWRESOLVE', 'SUCCEEDED']:
            if self.target_host is None:
                last_colon = args[3].rfind(':')
                self.target_host = args[3][:last_colon]
                self.target_port = int(args[3][last_colon + 1:])

            self.target_port = int(self.target_port)
            if self.state == 'NEW':
                if self.circuit is not None:
                    log.err(RuntimeError("Weird: circuit valid in NEW"))
                [x.stream_new(self) for x in self.listeners]
            else:
                [x.stream_succeeded(self) for x in self.listeners]

        elif self.state == 'REMAP':
            self.target_addr = maybe_ip_addr(args[3][:args[3].rfind(':')])

        elif self.state == 'CLOSED':
            if self.circuit:
                self.circuit.streams.remove(self)
            self.circuit = None
            self.maybe_call_closing_deferred()
            flags = self._create_flags(kw)
            [x.stream_closed(self, **flags) for x in self.listeners]

        elif self.state == 'FAILED':
            if self.circuit:
                self.circuit.streams.remove(self)
            self.circuit = None
            self.maybe_call_closing_deferred()
            # build lower-case version of all flags
            flags = self._create_flags(kw)
            [x.stream_failed(self, **flags) for x in self.listeners]

        elif self.state == 'SENTCONNECT':
            pass  # print 'SENTCONNECT',self,args

        elif self.state == 'DETACHED':
            if self.circuit:
                self.circuit.streams.remove(self)
                self.circuit = None

            # FIXME does this count as closed?
            # self.maybe_call_closing_deferred()
            flags = self._create_flags(kw)
            [x.stream_detach(self, **flags) for x in self.listeners]

        elif self.state in ['NEWRESOLVE', 'SENTRESOLVE']:
            pass  # print self.state, self, args

        else:
            raise RuntimeError("Unknown state: %s" % self.state)

        # see if we attached to a circuit. I believe this only happens
        # on a SENTCONNECT or REMAP. DETACHED is excluded so we don't
        # immediately re-add the circuit we just detached from
        if self.state not in ['CLOSED', 'FAILED', 'DETACHED']:
            cid = int(args[2])
            if cid == 0:
                if self.circuit and self in self.circuit.streams:
                    self.circuit.streams.remove(self)
                self.circuit = None

            else:
                if self.circuit is None:
                    self.circuit = self.circuit_container.find_circuit(cid)
                    if self not in self.circuit.streams:
                        self.circuit.streams.append(self)
                        for x in self.listeners:
                            x.stream_attach(self, self.circuit)

                else:
                    if self.circuit.id != cid:
                        log.err(
                            RuntimeError(
                                'Circuit ID changed from %d to %d.' %
                                (self.circuit.id, cid)
                            )
                        )
Example #12
0
 def _add_real_target(self, real_addr, circuit, d):
     # joy oh joy, ipaddress wants unicode, Twisted gives us bytes...
     real_host = maybe_ip_addr(six.text_type(real_addr.host))
     real_port = real_addr.port
     self._circuit_targets[(real_host, real_port)] = (circuit, d)
Example #13
0
    def test_create_ipaddr(self, ipaddr):
        def foo(blam):
            raise ValueError('testing')

        ipaddr.IPAddress.side_effect = foo
        ip = maybe_ip_addr('1.2.3.4')
Example #14
0
 def test_create_ipaddr(self, ipaddr):
     ip = maybe_ip_addr('1.2.3.4')
Example #15
0
    def update(self, args):
        if self.id is None:
            self.id = int(args[0])
        else:
            if self.id != int(args[0]):
                raise RuntimeError("Update for wrong stream.")

        kw = find_keywords(args)
        self.flags = kw

        if 'SOURCE_ADDR' in kw:
            last_colon = kw['SOURCE_ADDR'].rfind(':')
            self.source_addr = kw['SOURCE_ADDR'][:last_colon]
            if self.source_addr != '(Tor_internal)':
                self.source_addr = maybe_ip_addr(self.source_addr)
            self.source_port = int(kw['SOURCE_ADDR'][last_colon + 1:])

        self.state = args[1]
        # XXX why not using the state-machine stuff? ;)
        if self.state in ['NEW', 'NEWRESOLVE', 'SUCCEEDED']:
            if self.target_host is None:
                last_colon = args[3].rfind(':')
                self.target_host = args[3][:last_colon]
                self.target_port = int(args[3][last_colon + 1:])
                # target_host is often an IP address (newer tors? did
                # this change?) so we attempt to look it up in our
                # AddrMap and make it a name no matter what.
                if self._addrmap:
                    try:
                        h = self._addrmap.find(self.target_host)
                        self.target_host = h.name
                    except KeyError:
                        pass

            self.target_port = int(self.target_port)
            if self.state == 'NEW':
                if self.circuit is not None:
                    log.err(RuntimeError("Weird: circuit valid in NEW"))
                self._notify('stream_new', self)
            else:
                self._notify('stream_succeeded', self)

        elif self.state == 'REMAP':
            self.target_addr = maybe_ip_addr(args[3][:args[3].rfind(':')])

        elif self.state == 'CLOSED':
            if self.circuit:
                self.circuit.streams.remove(self)
            self.circuit = None
            self.maybe_call_closing_deferred()
            flags = self._create_flags(kw)
            self._notify('stream_closed', self, **flags)

        elif self.state == 'FAILED':
            if self.circuit:
                self.circuit.streams.remove(self)
            self.circuit = None
            self.maybe_call_closing_deferred()
            # build lower-case version of all flags
            flags = self._create_flags(kw)
            self._notify('stream_failed', self, **flags)

        elif self.state == 'SENTCONNECT':
            pass  # print 'SENTCONNECT',self,args

        elif self.state == 'DETACHED':
            if self.circuit:
                self.circuit.streams.remove(self)
                self.circuit = None

            # FIXME does this count as closed?
            # self.maybe_call_closing_deferred()
            flags = self._create_flags(kw)
            self._notify('stream_detach', self, **flags)

        elif self.state in ['NEWRESOLVE', 'SENTRESOLVE']:
            pass  # print self.state, self, args

        else:
            raise RuntimeError("Unknown state: %s" % self.state)

        # see if we attached to a circuit. I believe this only happens
        # on a SENTCONNECT or REMAP. DETACHED is excluded so we don't
        # immediately re-add the circuit we just detached from
        if self.state not in ['CLOSED', 'FAILED', 'DETACHED']:
            cid = int(args[2])
            if cid == 0:
                if self.circuit and self in self.circuit.streams:
                    self.circuit.streams.remove(self)
                self.circuit = None

            else:
                if self.circuit is None:
                    self.circuit = self.circuit_container.find_circuit(cid)
                    if self not in self.circuit.streams:
                        self.circuit.streams.append(self)
                        self._notify('stream_attach', self, self.circuit)

                else:
                    if self.circuit.id != cid:
                        log.err(
                            RuntimeError('Circuit ID changed from %d to %d.' %
                                         (self.circuit.id, cid)))
Example #16
0
    def update(self, args):
        ## print "update",self.id,args

        if self.id is None:
            self.id = int(args[0])
        else:
            if self.id != int(args[0]):
                raise RuntimeError("Update for wrong stream.")

        kw = find_keywords(args)
        self.flags = kw

        if 'SOURCE_ADDR' in kw:
            last_colon = kw['SOURCE_ADDR'].rfind(':')
            self.source_addr = kw['SOURCE_ADDR'][:last_colon]
            if self.source_addr != '(Tor_internal)':
                self.source_addr = maybe_ip_addr(self.source_addr)
            self.source_port = int(kw['SOURCE_ADDR'][last_colon + 1:])

        self.state = args[1]
        if self.state in ['NEW', 'NEWRESOLVE', 'SUCCEEDED']:
            if self.target_host is None:
                last_colon = args[3].rfind(':')
                self.target_host = args[3][:last_colon]
                self.target_port = int(args[3][last_colon + 1:])

            self.target_port = int(self.target_port)
            if self.state == 'NEW':
                if self.circuit is not None:
                    log.err(RuntimeError("Weird: circuit valid in NEW"))
                [x.stream_new(self) for x in self.listeners]
            else:
                [x.stream_succeeded(self) for x in self.listeners]

        elif self.state == 'REMAP':
            self.target_addr = maybe_ip_addr(args[3][:args[3].rfind(':')])

        elif self.state == 'CLOSED':
            if self.circuit:
                self.circuit.streams.remove(self)
            self.circuit = None
            self.maybe_call_closing_deferred()
            flags = self._create_flags(kw)
            [x.stream_closed(self, **flags) for x in self.listeners]

        elif self.state == 'FAILED':
            if self.circuit:
                self.circuit.streams.remove(self)
            self.circuit = None
            self.maybe_call_closing_deferred()
            # build lower-case version of all flags
            flags = self._create_flags(kw)
            [x.stream_failed(self, **flags) for x in self.listeners]

        elif self.state == 'SENTCONNECT':
            pass  # print 'SENTCONNECT',self,args

        elif self.state == 'DETACHED':
            if self.circuit:
                self.circuit.streams.remove(self)
                self.circuit = None

            ## FIXME does this count as closed?
            ##self.maybe_call_closing_deferred()
            flags = self._create_flags(kw)
            [x.stream_detach(self, **flags) for x in self.listeners]

        elif self.state in ['NEWRESOLVE', 'SENTRESOLVE']:
            pass  # print self.state, self, args

        else:
            raise RuntimeError("Unknown state: %s" % self.state)

        ## see if we attached to a circuit. I believe this only
        ## happens on a SENTCONNECT or REMAP. DETACHED is excluded so
        ## we don't immediately re-add the circuit we just detached
        ## from
        if self.state not in ['CLOSED', 'FAILED', 'DETACHED']:
            cid = int(args[2])
            if cid == 0:
                if self.circuit and self in self.circuit.streams:
                    self.circuit.streams.remove(self)
                self.circuit = None

            else:
                if self.circuit is None:
                    self.circuit = self.circuit_container.find_circuit(cid)
                    if self not in self.circuit.streams:
                        self.circuit.streams.append(self)
                        [x.stream_attach(self, self.circuit) for x in self.listeners]

                else:
                    if self.circuit.id != cid:
                        log.err(RuntimeError('Circuit ID changed from %d to %d.' % (self.circuit.id, cid)))
Example #17
0
 def test_create_ipaddr(self, ipaddr):
     def foo(blam):
         raise ValueError('testing')
     ipaddr.ip_address.side_effect = foo
     ip = maybe_ip_addr('1.2.3.4')
Example #18
0
 def test_create_ipaddr(self):
     ip = maybe_ip_addr('1.2.3.4')
     self.assertTrue(isinstance(ip, ipaddress.IPv4Address))
Example #19
0
 def test_ipv6_remap(self):
     stream = Stream(self)
     stream.update("1234 REMAP 0 ::1:80 SOURCE_ADDR=127.0.0.1:57349 PURPOSE=USER".split())
     self.assertEqual(stream.target_addr, maybe_ip_addr('::1'))
Example #20
0
 def test_ipv6_remap(self):
     stream = Stream(self)
     stream.update(
         "1234 REMAP 0 ::1:80 SOURCE_ADDR=127.0.0.1:57349 PURPOSE=USER".
         split())
     self.assertEqual(stream.target_addr, maybe_ip_addr('::1'))
Example #21
0
    def update(self, args):
        # print "update",self.id,args

        if self.id is None:
            self.id = int(args[0])
        else:
            if self.id != int(args[0]):
                raise RuntimeError("Update for wrong stream.")

        kw = find_keywords(args)
        self.flags = kw

        if "SOURCE_ADDR" in kw:
            last_colon = kw["SOURCE_ADDR"].rfind(":")
            self.source_addr = kw["SOURCE_ADDR"][:last_colon]
            if self.source_addr != "(Tor_internal)":
                self.source_addr = maybe_ip_addr(self.source_addr)
            self.source_port = int(kw["SOURCE_ADDR"][last_colon + 1 :])

        self.state = args[1]
        # XXX why not using the state-machine stuff? ;)
        if self.state in ["NEW", "NEWRESOLVE", "SUCCEEDED"]:
            if self.target_host is None:
                last_colon = args[3].rfind(":")
                self.target_host = args[3][:last_colon]
                self.target_port = int(args[3][last_colon + 1 :])
                # target_host is often an IP address (newer tors? did
                # this change?) so we attempt to look it up in our
                # AddrMap and make it a name no matter what.
                if self._addrmap:
                    try:
                        h = self._addrmap.find(self.target_host)
                        self.target_host = h.name
                    except KeyError:
                        pass

            self.target_port = int(self.target_port)
            if self.state == "NEW":
                if self.circuit is not None:
                    log.err(RuntimeError("Weird: circuit valid in NEW"))
                self._notify("stream_new", self)
            else:
                self._notify("stream_succeeded", self)

        elif self.state == "REMAP":
            self.target_addr = maybe_ip_addr(args[3][: args[3].rfind(":")])

        elif self.state == "CLOSED":
            if self.circuit:
                self.circuit.streams.remove(self)
            self.circuit = None
            self.maybe_call_closing_deferred()
            flags = self._create_flags(kw)
            self._notify("stream_closed", self, **flags)

        elif self.state == "FAILED":
            if self.circuit:
                self.circuit.streams.remove(self)
            self.circuit = None
            self.maybe_call_closing_deferred()
            # build lower-case version of all flags
            flags = self._create_flags(kw)
            self._notify("stream_failed", self, **flags)

        elif self.state == "SENTCONNECT":
            pass  # print 'SENTCONNECT',self,args

        elif self.state == "DETACHED":
            if self.circuit:
                self.circuit.streams.remove(self)
                self.circuit = None

            # FIXME does this count as closed?
            # self.maybe_call_closing_deferred()
            flags = self._create_flags(kw)
            self._notify("stream_detach", self, **flags)

        elif self.state in ["NEWRESOLVE", "SENTRESOLVE"]:
            pass  # print self.state, self, args

        else:
            raise RuntimeError("Unknown state: %s" % self.state)

        # see if we attached to a circuit. I believe this only happens
        # on a SENTCONNECT or REMAP. DETACHED is excluded so we don't
        # immediately re-add the circuit we just detached from
        if self.state not in ["CLOSED", "FAILED", "DETACHED"]:
            cid = int(args[2])
            if cid == 0:
                if self.circuit and self in self.circuit.streams:
                    self.circuit.streams.remove(self)
                self.circuit = None

            else:
                if self.circuit is None:
                    self.circuit = self.circuit_container.find_circuit(cid)
                    if self not in self.circuit.streams:
                        self.circuit.streams.append(self)
                        self._notify("stream_attach", self, self.circuit)

                else:
                    if self.circuit.id != cid:
                        log.err(RuntimeError("Circuit ID changed from %d to %d." % (self.circuit.id, cid)))
Example #22
0
    def update(self, args):
        if self.id is None:
            self.id = int(args[0])
        else:
            if self.id != int(args[0]):
                raise RuntimeError("Update for wrong stream.")

        kw = find_keywords(args)
        self.flags = kw

        if 'SOURCE_ADDR' in kw:
            last_colon = kw['SOURCE_ADDR'].rfind(':')
            self.source_addr = kw['SOURCE_ADDR'][:last_colon]
            if self.source_addr != '(Tor_internal)':
                self.source_addr = maybe_ip_addr(self.source_addr)
            self.source_port = int(kw['SOURCE_ADDR'][last_colon + 1:])

        self.state = args[1]
        # XXX why not using the state-machine stuff? ;)
        if self.state in ['NEW', 'NEWRESOLVE', 'SUCCEEDED']:
            if self.target_host is None:
                last_colon = args[3].rfind(':')
                self.target_host = args[3][:last_colon]
                self.target_port = int(args[3][last_colon + 1:])
                # target_host is often an IP address (newer tors? did
                # this change?) so we attempt to look it up in our
                # AddrMap and make it a name no matter what.
                if self._addrmap:
                    try:
                        h = self._addrmap.find(self.target_host)
                        self.target_host = h.name
                    except KeyError:
                        pass

            self.target_port = int(self.target_port)
            if self.state == 'NEW':
                if self.circuit is not None:
                    log.err(RuntimeError("Weird: circuit valid in NEW"))
                self._notify('stream_new', self)
            else:
                self._notify('stream_succeeded', self)

        elif self.state == 'REMAP':
            self.target_addr = maybe_ip_addr(args[3][:args[3].rfind(':')])

        elif self.state == 'CLOSED':
            if self.circuit:
                self.circuit.streams.remove(self)
            self.circuit = None
            self.maybe_call_closing_deferred()
            flags = self._create_flags(kw)
            self._notify('stream_closed', self, **flags)

        elif self.state == 'FAILED':
            if self.circuit:
                self.circuit.streams.remove(self)
            self.circuit = None
            self.maybe_call_closing_deferred()
            # build lower-case version of all flags
            flags = self._create_flags(kw)
            self._notify('stream_failed', self, **flags)

        elif self.state == 'SENTCONNECT':
            pass  # print 'SENTCONNECT',self,args

        elif self.state == 'DETACHED':
            if self.circuit:
                self.circuit.streams.remove(self)
                self.circuit = None

            # FIXME does this count as closed?
            # self.maybe_call_closing_deferred()
            flags = self._create_flags(kw)
            self._notify('stream_detach', self, **flags)

        elif self.state in ['NEWRESOLVE', 'SENTRESOLVE']:
            pass  # print self.state, self, args

        else:
            raise RuntimeError("Unknown state: %s" % self.state)

        # see if we attached to a circuit. I believe this only happens
        # on a SENTCONNECT or REMAP. DETACHED is excluded so we don't
        # immediately re-add the circuit we just detached from
        if self.state not in ['CLOSED', 'FAILED', 'DETACHED']:
            cid = int(args[2])
            if cid == 0:
                if self.circuit and self in self.circuit.streams:
                    self.circuit.streams.remove(self)
                self.circuit = None

            else:
                if self.circuit is None:
                    self.circuit = self.circuit_container.find_circuit(cid)
                    if self not in self.circuit.streams:
                        self.circuit.streams.append(self)
                        self._notify('stream_attach', self, self.circuit)

                else:
                    # XXX I am seeing this from torexitscan (*and*
                    # from my TorNS thing, so I think it's some kind
                    # of 'consistent' behavior out of Tor) so ... this
                    # is probably when we're doing stream-attachment
                    # stuff? maybe the stream gets assigned a circuit
                    # 'provisionally' and then it's changed?
                    # ...yup, looks like it!
                    if self.circuit.id != cid:
                        # you can get SENTCONNECT twice in a row (for example) with different circuit-ids if there is something (e.g. another txtorcon) doing R
                        log.err(
                            RuntimeError(
                                'Circuit ID changed from %d to %d state=%s.' %
                                (self.circuit.id, cid, self.state)))
Example #23
0
    def update(self, args):
        if self.id is None:
            self.id = int(args[0])
        else:
            if self.id != int(args[0]):
                raise RuntimeError("Update for wrong stream.")

        kw = find_keywords(args)
        self.flags = kw

        if 'SOURCE_ADDR' in kw:
            last_colon = kw['SOURCE_ADDR'].rfind(':')
            self.source_addr = kw['SOURCE_ADDR'][:last_colon]
            if self.source_addr != '(Tor_internal)':
                self.source_addr = maybe_ip_addr(self.source_addr)
            self.source_port = int(kw['SOURCE_ADDR'][last_colon + 1:])

        self.state = args[1]
        # XXX why not using the state-machine stuff? ;)
        if self.state in ['NEW', 'NEWRESOLVE', 'SUCCEEDED']:
            if self.target_host is None:
                last_colon = args[3].rfind(':')
                self.target_host = args[3][:last_colon]
                self.target_port = int(args[3][last_colon + 1:])
                # target_host is often an IP address (newer tors? did
                # this change?) so we attempt to look it up in our
                # AddrMap and make it a name no matter what.
                if self._addrmap:
                    try:
                        h = self._addrmap.find(self.target_host)
                        self.target_host = h.name
                    except KeyError:
                        pass

            self.target_port = int(self.target_port)
            if self.state == 'NEW':
                if self.circuit is not None:
                    log.err(RuntimeError("Weird: circuit valid in NEW"))
                self._notify('stream_new', self)
            else:
                self._notify('stream_succeeded', self)

        elif self.state == 'REMAP':
            self.target_addr = maybe_ip_addr(args[3][:args[3].rfind(':')])

        elif self.state == 'CLOSED':
            if self.circuit:
                self.circuit.streams.remove(self)
            self.circuit = None
            self.maybe_call_closing_deferred()
            flags = self._create_flags(kw)
            self._notify('stream_closed', self, **flags)

        elif self.state == 'FAILED':
            if self.circuit:
                self.circuit.streams.remove(self)
            self.circuit = None
            self.maybe_call_closing_deferred()
            # build lower-case version of all flags
            flags = self._create_flags(kw)
            self._notify('stream_failed', self, **flags)

        elif self.state == 'SENTCONNECT':
            pass  # print 'SENTCONNECT',self,args

        elif self.state == 'DETACHED':
            if self.circuit:
                self.circuit.streams.remove(self)
                self.circuit = None

            # FIXME does this count as closed?
            # self.maybe_call_closing_deferred()
            flags = self._create_flags(kw)
            self._notify('stream_detach', self, **flags)

        elif self.state in ['NEWRESOLVE', 'SENTRESOLVE']:
            pass  # print self.state, self, args

        else:
            raise RuntimeError("Unknown state: %s" % self.state)

        # see if we attached to a circuit. I believe this only happens
        # on a SENTCONNECT or REMAP. DETACHED is excluded so we don't
        # immediately re-add the circuit we just detached from
        if self.state not in ['CLOSED', 'FAILED', 'DETACHED']:
            cid = int(args[2])
            if cid == 0:
                if self.circuit and self in self.circuit.streams:
                    self.circuit.streams.remove(self)
                self.circuit = None

            else:
                if self.circuit is None:
                    self.circuit = self.circuit_container.find_circuit(cid)
                    if self not in self.circuit.streams:
                        self.circuit.streams.append(self)
                        self._notify('stream_attach', self, self.circuit)

                else:
                    # XXX I am seeing this from torexitscan (*and*
                    # from my TorNS thing, so I think it's some kind
                    # of 'consistent' behavior out of Tor) so ... this
                    # is probably when we're doing stream-attachment
                    # stuff? maybe the stream gets assigned a circuit
                    # 'provisionally' and then it's changed?
                    # ...yup, looks like it!
                    if self.circuit.id != cid:
                        # you can get SENTCONNECT twice in a row (for example) with different circuit-ids if there is something (e.g. another txtorcon) doing R
                        log.err(
                            RuntimeError(
                                'Circuit ID changed from %d to %d state=%s.' %
                                (self.circuit.id, cid, self.state)
                            )
                        )
Example #24
0
 def _add_real_target(self, real_addr, circuit, d):
     # joy oh joy, ipaddress wants unicode, Twisted gives us bytes...
     real_host = maybe_ip_addr(six.text_type(real_addr.host))
     real_port = real_addr.port
     self._circuit_targets[(real_host, real_port)] = (circuit, d)
Example #25
0
 def test_create_ipaddr(self):
     ip = maybe_ip_addr('1.2.3.4')
     self.assertTrue(isinstance(ip, ipaddress.IPv4Address))
Example #26
0
 def test_create_ipaddr_fail(self, ipaddr):
     def foo(blam):
         raise ValueError('testing')
     ipaddr.ip_address.side_effect = foo
     ip = maybe_ip_addr('1.2.3.4')
     self.assertTrue(isinstance(ip, type('1.2.3.4')))
Example #27
0
 def test_create_ipaddr(self, ipaddr):
     ip = maybe_ip_addr('1.2.3.4')