def test_connections(self, open_mock, readlink_mock, listdir_mock): """ Tests the connections function. """ pid = 1111 listdir_mock.side_effect = lambda param: { '/proc/%s/fd' % pid: ['1', '2', '3', '4'], }[param] readlink_mock.side_effect = lambda param: { '/proc/%s/fd/1' % pid: 'socket:[99999999]', '/proc/%s/fd/2' % pid: 'socket:[IIIIIIII]', '/proc/%s/fd/3' % pid: 'pipe:[30303]', '/proc/%s/fd/4' % pid: 'pipe:[40404]', }[param] tcp = '\n 0: 11111111:1111 22222222:2222 01 44444444:44444444 55:55555555 66666666 1111 8 99999999' udp = '\n A: BBBBBBBB:BBBB CCCCCCCC:CCCC DD EEEEEEEE:EEEEEEEE FF:FFFFFFFF GGGGGGGG 1111 H IIIIIIII' open_mock.side_effect = lambda param: { '/proc/net/tcp': StringIO(tcp), '/proc/net/udp': StringIO(udp) }[param] # tests the edge case of pid = 0 self.assertEqual([], proc.connections(0)) expected_results = [ ('17.17.17.17', 4369, '34.34.34.34', 8738, 'tcp'), ('187.187.187.187', 48059, '204.204.204.204', 52428, 'udp'), ] self.assertEqual(expected_results, proc.connections(pid))
def test_connections_ipv6_by_user(self, open_mock, getpwnam_mock, path_exists_mock): """ Tests the connections function with ipv6 addresses. """ getpwnam_mock('me').pw_uid = 106 path_exists_mock.side_effect = lambda param: { '/proc/net/tcp6': True, '/proc/net/udp6': False }[param] open_mock.side_effect = lambda param, mode: { '/proc/net/tcp': io.BytesIO(TITLE_LINE), '/proc/net/tcp6': io.BytesIO(TCP6_CONTENT), '/proc/net/udp': io.BytesIO(TITLE_LINE), }[param] expected = [ Connection('0000:0000:0000:0000:0000:ffff:0509:9e4b', 5222, '0000:0000:0000:0000:0000:ffff:4e36:8621', 38330, 'tcp', True), Connection('2a01:04f8:0190:514a:0000:0000:0000:0002', 5269, '2001:06f8:126f:0011:0000:0000:0000:0026', 50594, 'tcp', True), Connection('0000:0000:0000:0000:0000:ffff:0509:9e4b', 5222, '0000:0000:0000:0000:0000:ffff:4e36:8621', 38174, 'tcp', True), ] self.assertEqual(expected, proc.connections(user='******'))
def test_connections(self): """ Checks for our control port in the stem.util.proc.connections output if we have one. """ runner = test.runner.get_runner() if not proc.is_available(): test.runner.skip(self, '(proc unavailable)') return elif test.runner.Torrc.PORT not in runner.get_options(): test.runner.skip(self, '(no control port)') return elif not test.runner.get_runner().is_ptraceable(): test.runner.skip(self, '(DisableDebuggerAttachment is set)') return elif not os.access('/proc/net/tcp', os.R_OK) or not os.access('/proc/net/udp', os.R_OK): test.runner.skip(self, '(proc lacks read permissions)') return # making a controller connection so that we have something to query for with runner.get_tor_socket(): tor_pid = test.runner.get_runner().get_pid() for conn in proc.connections(tor_pid): if ('127.0.0.1', test.runner.CONTROL_PORT) == conn[:2]: return self.fail()
def test_connections(self): """ Checks for our control port in the stem.util.proc.connections output if we have one. """ runner = test.runner.get_runner() if test.runner.Torrc.PORT not in runner.get_options(): self.skiTestp('(no control port)') return elif not os.access('/proc/net/tcp', os.R_OK) or not os.access( '/proc/net/udp', os.R_OK): self.skipTest('(proc lacks read permissions)') return # making a controller connection so that we have something to query for with runner.get_tor_socket(): tor_pid = test.runner.get_runner().get_pid() for conn in proc.connections(tor_pid): if ('127.0.0.1', test.runner.CONTROL_PORT) == conn[:2]: return self.fail()
def test_connections_ipv6_by_user(self, open_mock, getpwnam_mock, path_exists_mock): """ Tests the connections function with ipv6 addresses. """ getpwnam_mock('me').pw_uid = 106 path_exists_mock.side_effect = lambda param: { '/proc/net/tcp6': True, '/proc/net/udp6': False }[param] open_mock.side_effect = lambda param, mode: { '/proc/net/tcp': io.BytesIO(b''), '/proc/net/tcp6': io.BytesIO(TCP6_CONTENT), '/proc/net/udp': io.BytesIO(b''), }[param] expected_results = [ Connection('0000:0000:0000:0000:0000:ffff:0509:9e4b', 5222, '0000:0000:0000:0000:0000:ffff:4e36:8621', 38330, 'tcp', True), Connection('2a01:04f8:0190:514a:0000:0000:0000:0002', 5269, '2001:06f8:126f:0011:0000:0000:0000:0026', 50594, 'tcp', True), Connection('0000:0000:0000:0000:0000:ffff:0509:9e4b', 5222, '0000:0000:0000:0000:0000:ffff:4e36:8621', 38174, 'tcp', True), ] self.assertEqual(expected_results, proc.connections(user = '******'))
def test_connections_ipv6(self, open_mock, readlink_mock, path_exists_mock, listdir_mock): """ Tests the connections function with ipv6 addresses. """ pid = 1111 listdir_mock.side_effect = lambda param: { '/proc/%s/fd' % pid: ['1', '2'], }[param] readlink_mock.side_effect = lambda param: { '/proc/%s/fd/1' % pid: 'socket:[42088802]', '/proc/%s/fd/2' % pid: 'socket:[41691357]', }[param] path_exists_mock.side_effect = lambda param: { '/proc/net/tcp6': True, '/proc/net/udp6': False }[param] open_mock.side_effect = lambda param, mode: { '/proc/net/tcp': io.BytesIO(b''), '/proc/net/tcp6': io.BytesIO(TCP6_CONTENT), '/proc/net/udp': io.BytesIO(b''), }[param] expected_results = [ Connection('2a01:04f8:0190:514a:0000:0000:0000:0002', 443, '2001:0638:a000:4140:0000:0000:ffff:0189', 40435, 'tcp', True), Connection('2a01:04f8:0190:514a:0000:0000:0000:0002', 443, '2001:0858:0002:0002:aabb:0000:563b:1526', 44469, 'tcp', True), ] self.assertEqual(expected_results, proc.connections(pid = pid))
def test_connections(self, open_mock, readlink_mock, path_exists_mock, listdir_mock): """ Tests the connections function. """ pid = 1111 listdir_mock.side_effect = lambda param: { '/proc/%s/fd' % pid: ['1', '2', '3', '4'], }[param] readlink_mock.side_effect = lambda param: { '/proc/%s/fd/1' % pid: 'socket:[99999999]', '/proc/%s/fd/2' % pid: 'socket:[IIIIIIII]', '/proc/%s/fd/3' % pid: 'pipe:[30303]', '/proc/%s/fd/4' % pid: 'pipe:[40404]', }[param] tcp = TITLE_LINE + b'\n 0: 11111111:1111 22222222:2222 01 44444444:44444444 55:55555555 66666666 1111 8 99999999' udp = TITLE_LINE + b'\n A: BBBBBBBB:BBBB CCCCCCCC:CCCC DD EEEEEEEE:EEEEEEEE FF:FFFFFFFF GGGGGGGG 1111 H IIIIIIII' path_exists_mock.side_effect = lambda param: { '/proc/net/tcp': True, '/proc/net/tcp6': False, '/proc/net/udp': True, '/proc/net/udp6': False }[param] open_mock.side_effect = lambda param, mode: { '/proc/net/tcp': io.BytesIO(tcp), '/proc/net/udp': io.BytesIO(udp) }[param] expected_results = [ Connection('17.17.17.17', 4369, '34.34.34.34', 8738, 'tcp', False), Connection('187.187.187.187', 48059, '204.204.204.204', 52428, 'udp', False), ] self.assertEqual(expected_results, proc.connections(pid))
def test_high_connection_count(self, open_mock, readlink_mock, path_exists_mock, listdir_mock): """ When we have over ten thousand connections the 'SL' column's width changes. Checking that we account for this. """ pid = 1111 listdir_mock.side_effect = lambda param: { '/proc/%s/fd' % pid: ['1', '2', '3', '4'], }[param] readlink_mock.side_effect = lambda param: { '/proc/%s/fd/1' % pid: 'socket:[99999999]', '/proc/%s/fd/2' % pid: 'socket:[88888888]', '/proc/%s/fd/3' % pid: 'socket:[77777777]', '/proc/%s/fd/4' % pid: 'pipe:[30303]', '/proc/%s/fd/5' % pid: 'pipe:[40404]', }[param] path_exists_mock.side_effect = lambda param: { '/proc/net/tcp6': False, '/proc/net/udp6': False }[param] open_mock.side_effect = lambda param, mode: { '/proc/net/tcp': io.BytesIO(SL_WIDTH_CHANGE), '/proc/net/udp': io.BytesIO(TITLE_LINE) }[param] expected = [ Connection('17.17.17.17', 4369, '51.34.34.34', 8772, 'tcp', False), Connection('34.34.34.34', 8738, '68.51.51.51', 13141, 'tcp', False), Connection('51.51.51.51', 13107, '85.68.68.68', 17510, 'tcp', False), ] self.assertEqual(expected, proc.connections(pid))
def test_connections(self, open_mock, readlink_mock, path_exists_mock, listdir_mock): """ Tests the connections function. """ pid = 1111 listdir_mock.side_effect = lambda param: { '/proc/%s/fd' % pid: ['1', '2', '3', '4'], }[param] readlink_mock.side_effect = lambda param: { '/proc/%s/fd/1' % pid: 'socket:[99999999]', '/proc/%s/fd/2' % pid: 'socket:[IIIIIIII]', '/proc/%s/fd/3' % pid: 'pipe:[30303]', '/proc/%s/fd/4' % pid: 'pipe:[40404]', }[param] tcp = b'\n 0: 11111111:1111 22222222:2222 01 44444444:44444444 55:55555555 66666666 1111 8 99999999' udp = b'\n A: BBBBBBBB:BBBB CCCCCCCC:CCCC DD EEEEEEEE:EEEEEEEE FF:FFFFFFFF GGGGGGGG 1111 H IIIIIIII' path_exists_mock.side_effect = lambda param: { '/proc/net/tcp': True, '/proc/net/tcp6': False, '/proc/net/udp': True, '/proc/net/udp6': False }[param] open_mock.side_effect = lambda param, mode: { '/proc/net/tcp': io.BytesIO(tcp), '/proc/net/udp': io.BytesIO(udp) }[param] expected_results = [ Connection('17.17.17.17', 4369, '34.34.34.34', 8738, 'tcp', False), Connection('187.187.187.187', 48059, '204.204.204.204', 52428, 'udp', False), ] self.assertEqual(expected_results, proc.connections(pid))
def _task(self, process_pid, process_name): if self._custom_resolver: resolver = self._custom_resolver is_default_resolver = False elif self._resolvers: resolver = self._resolvers[0] is_default_resolver = True else: return False # nothing to resolve with try: start_time = time.time() new_connections, new_start_times = [], {} if resolver == CustomResolver.INFERENCE: # provide connections going to a relay or one of our tor ports connections = [] controller = tor_controller() consensus_tracker = get_consensus_tracker() relay_ports = set( controller.get_ports(stem.control.Listener.OR, [])) relay_ports.update( controller.get_ports(stem.control.Listener.DIR, [])) relay_ports.update( controller.get_ports(stem.control.Listener.CONTROL, [])) for conn in proc.connections(user=controller.get_user(None)): if conn.remote_port in consensus_tracker.get_relay_fingerprints( conn.remote_address): connections.append(conn) # outbound to another relay elif conn.local_port in relay_ports: connections.append(conn) else: connections = connection.get_connections( resolver, process_pid=process_pid, process_name=process_name) for conn in connections: conn_start_time, is_legacy = self._start_times.get( conn, (start_time, self._is_first_run)) new_start_times[conn] = (conn_start_time, is_legacy) new_connections.append( Connection(conn_start_time, is_legacy, *conn)) self._connections = new_connections self._start_times = new_start_times self._is_first_run = False runtime = time.time() - start_time if is_default_resolver: self._failure_count = 0 # Reduce our rate if connection resolution is taking a long time. This is # most often an issue for extremely busy relays. min_rate = 100 * runtime if self.get_rate() < min_rate: self._rate_too_low_count += 1 if self._rate_too_low_count >= 3: min_rate += 1 # little extra padding so we don't frequently update this self.set_rate(min_rate) self._rate_too_low_count = 0 stem.util.log.debug( 'connection lookup time increasing to %0.1f seconds per call' % min_rate) else: self._rate_too_low_count = 0 return True except IOError as exc: stem.util.log.info(str(exc)) # Fail over to another resolver if we've repeatedly been unable to use # this one. if is_default_resolver: self._failure_count += 1 if self._failure_count >= 3: self._resolvers.pop(0) self._failure_count = 0 if self._resolvers: stem.util.log.notice( 'Unable to query connections with %s, trying %s' % (resolver, self._resolvers[0])) else: stem.util.log.notice(UNABLE_TO_USE_ANY_RESOLVER_MSG) return False
def _task(self, process_pid, process_name): if self._custom_resolver: resolver = self._custom_resolver is_default_resolver = False elif self._resolvers: resolver = self._resolvers[0] is_default_resolver = True else: return False # nothing to resolve with try: start_time = time.time() new_connections, new_start_times = [], {} if resolver == CustomResolver.INFERENCE: # provide connections going to a relay or one of our tor ports connections = [] controller = tor_controller() consensus_tracker = get_consensus_tracker() for conn in proc.connections(user = controller.get_user(None)): if conn.remote_port in consensus_tracker.get_relay_fingerprints(conn.remote_address): connections.append(conn) # outbound to another relay elif conn.local_port in controller.get_ports(stem.control.Listener.OR, []): connections.append(conn) # inbound to our ORPort elif conn.local_port in controller.get_ports(stem.control.Listener.DIR, []): connections.append(conn) # inbound to our DirPort elif conn.local_port in controller.get_ports(stem.control.Listener.CONTROL, []): connections.append(conn) # controller connection else: connections = connection.get_connections(resolver, process_pid = process_pid, process_name = process_name) for conn in connections: conn_start_time, is_legacy = self._start_times.get(conn, (start_time, self._is_first_run)) new_start_times[conn] = (conn_start_time, is_legacy) new_connections.append(Connection(conn_start_time, is_legacy, *conn)) self._connections = new_connections self._start_times = new_start_times self._is_first_run = False runtime = time.time() - start_time if is_default_resolver: self._failure_count = 0 # Reduce our rate if connection resolution is taking a long time. This is # most often an issue for extremely busy relays. min_rate = 100 * runtime if self.get_rate() < min_rate: self._rate_too_low_count += 1 if self._rate_too_low_count >= 3: min_rate += 1 # little extra padding so we don't frequently update this self.set_rate(min_rate) self._rate_too_low_count = 0 log.debug('tracker.lookup_rate_increased', seconds = "%0.1f" % min_rate) else: self._rate_too_low_count = 0 return True except IOError as exc: log.info('wrap', text = exc) # Fail over to another resolver if we've repeatedly been unable to use # this one. if is_default_resolver: self._failure_count += 1 if self._failure_count >= 3: self._resolvers.pop(0) self._failure_count = 0 if self._resolvers: log.notice( 'tracker.unable_to_use_resolver', old_resolver = resolver, new_resolver = self._resolvers[0], ) else: log.notice('tracker.unable_to_use_all_resolvers') return False