diff --git a/Makefile b/Makefile index 343a61f..737b472 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,7 @@ PREFIX=/usr/local PYTHON_EXE_MSYS=${PREFIX}/bin/python3.sh +PIP_EXE_MSYS=${PREFIX}/bin/pip3.sh LOCAL_DOCTEST=${PREFIX}/bin/toxcore_run_doctest3.bash DOCTEST=${LOCAL_DOCTEST} MOD=stem_examples @@ -12,6 +13,9 @@ check:: lint:: sh .pylint.sh +xinstall:: + ${PIP_EXE_MSYS} install --target ${PREFIX}/lib/python3.11/site-packages/ --upgrade . + rsync:: bash .rsync.sh @@ -22,6 +26,8 @@ install:: test:: echo src/${MOD}/check_digests.py TOR_CONTROLLER_PASSWORD=${PASS} src/${MOD}/check_digests.py + echo src/${MOD}/interpreter.py + TOR_CONTROLLER_PASSWORD=${PASS} src/${MOD}/interpreter.py echo src/${MOD}/connection_resolution.py sudo env TOR_CONTROLLER_PASSWORD=${PASS} src/${MOD}/connection_resolution.py # broken because this site fails: http://128.31.0.39:9131/tor/status-vote diff --git a/setup.cfg b/setup.cfg index c077948..460a28f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -34,9 +34,8 @@ packages=find: where=src [options.entry_points] -console_scripts = - phantompy = phantompy.__main__:iMain - exclude_badExits = exclude_badExits:iMain +#console_scripts = +# exclude_badExits = exclude_badExits:iMain [easy_install] zip_ok = false diff --git a/src/stem_examples/check_digests.py b/src/stem_examples/check_digests.py index 512d825..6da8649 100755 --- a/src/stem_examples/check_digests.py +++ b/src/stem_examples/check_digests.py @@ -110,9 +110,9 @@ if __name__ == '__main__': else: sKNOWN_ONION = 'facebookwkhpilnemxj7asaniu7vnjjbiltxjqhye3mhbshg7kx5tfyd' # facebook LOG.info("Getting some FPs from a sKNOWN_ONION") - from stem_examples.introduction_points import lMain + from stem_examples.introduction_points import lMain as lIPMain with ignoreStdout(): - lArgs = lMain([sKNOWN_ONION]) + lArgs = lIPMain([sKNOWN_ONION]) LOG.info(f"Got {len(lArgs)} FPs from a sKNOWN_ONION") i = iMain(lArgs) diff --git a/src/stem_examples/exit_used.py b/src/stem_examples/exit_used.py index 520b007..4fdf005 100755 --- a/src/stem_examples/exit_used.py +++ b/src/stem_examples/exit_used.py @@ -20,7 +20,9 @@ from stem_examples.tor_controller import get_controller global COUNT, IMAX COUNT=0 -IMAX = 0 +global IMAX +IMAX = 10 +LOG = logging.getLogger() def stream_event(controller, event): global COUNT, IMAX @@ -42,7 +44,7 @@ def stream_event(controller, event): LOG.info("") -def iMain(): +def iMain(lArgs=None): password = os.environ.get('TOR_CONTROLLER_PASSWORD') if os.path.exists('/run/tor/control'): @@ -50,16 +52,14 @@ def iMain(): else: controller = get_controller(password=password, port=9051) - if IMAX > 0: + if IMAX <= 0: LOG.info("Please wait for requests for tor exits. Press 'enter' to end.") print("") stream_listener = functools.partial(stream_event, controller) controller.add_event_listener(stream_listener, EventType.STREAM) - input() if __name__ == '__main__': from stem_examples.stem_utils import vsetup_logging - LOG = logging.getLogger() if len(sys.argv) > 1: IMAX = int(sys.argv[1]) else: @@ -69,13 +69,17 @@ if __name__ == '__main__': else: log_level = 20 vsetup_logging(LOG, log_level) + if len(sys.argv) > 1: + IMAX = int(sys.argv[1]) + del sys.argv[1] try: iMain() + input() i = 0 except KeyboardInterrupt as e: i = 0 except Exception as e: - LOG.exception(f"Exception {e}") + LOG.exception(f"Exception {e}", exc_info=True) i = 1 sys.exit(i) diff --git a/src/stem_examples/interpreter.py b/src/stem_examples/interpreter.py new file mode 100644 index 0000000..bd4be2f --- /dev/null +++ b/src/stem_examples/interpreter.py @@ -0,0 +1,57 @@ +#!/usr/local/bin/python3.sh +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- +__doc__ = """List Outdated Relays + +Time marches on. Tor makes new releases, and at some point needs to drop +support for old ones. Below is the script we used on ticket 9476 to reach out +to relay operators that needed to upgrade. + +https://stem.torproject.org/tutorials/examples/outdated_relays.html +""" + +import os +import sys +import logging + +import stem.interpreter.commands +from stem.descriptor.remote import DescriptorDownloader +from stem_examples.tor_controller import get_controller +from stem.version import Version + +from tor_controller import set_socks_proxy, unset_socks_proxy + +LOG = logging.getLogger() + +def iMain(lArgs=None): + if not lArgs: + lArgs = ['GETINFO' 'version'] + password = os.environ.get('TOR_CONTROLLER_PASSWORD') + if os.path.exists('/run/tor/control'): + controller = get_controller(password=password, unix='/run/tor/control') + else: + controller = get_controller(password=password, port=9051) + interpreter = stem.interpreter.commands.ControlInterpreter(controller) + run_cmd = ' '.join(lArgs) + interpreter.run_command(run_cmd, print_response = True) + return 0 + +if __name__ == '__main__': +# set_socks_proxy() + from stem_examples.stem_utils import vsetup_logging + if os.environ.get('DEBUG', ''): + log_level = 10 + else: + log_level = 20 + vsetup_logging(LOG, log_level) + try: + l = iMain(sys.argv[1:]) + if l: print(l) + i = 0 + except KeyboardInterrupt as e: + i = 0 + except Exception as e: + LOG.exception(f"Exception {e}") + i = 1 + finally: + unset_socks_proxy() + sys.exit(i) diff --git a/src/stem_examples/mappaddress.py b/src/stem_examples/mappaddress.py index 0e1a40e..28e32fc 100755 --- a/src/stem_examples/mappaddress.py +++ b/src/stem_examples/mappaddress.py @@ -22,7 +22,6 @@ from stem.control import EventType, Controller # from tor_controller import set_socks_proxy, unset_socks_proxy from stem_examples.tor_controller import get_controller -from stem_examples.stem_utils import vsetup_logging global LOG import logging @@ -34,7 +33,7 @@ def sMapaddressResolv(target, iPort=9051): if os.path.exists('/run/tor/control'): controller = get_controller(password=password, unix='/run/tor/control') else: - controller = get_controller(password=password, port=9051) + controller = get_controller(password=password, port=iPort) map_dict = {"0.0.0.0": target} map_ret = controller.map_address(map_dict) @@ -44,6 +43,7 @@ def sMapaddressResolv(target, iPort=9051): LOG.exception(e) if __name__ == '__main__': + from stem_examples.stem_utils import vsetup_logging if os.environ.get('DEBUG', ''): log_level = 10 else: diff --git a/src/stem_examples/outdated_relays.py b/src/stem_examples/outdated_relays.py index d3719f6..9f68dab 100755 --- a/src/stem_examples/outdated_relays.py +++ b/src/stem_examples/outdated_relays.py @@ -20,7 +20,7 @@ from tor_controller import set_socks_proxy, unset_socks_proxy LOG = logging.getLogger() -def iMain(): +def iMain(lArgs=None): downloader = DescriptorDownloader(use_mirrors=True) count, with_contact = 0, 0 elts = downloader.get_server_descriptors() @@ -47,7 +47,7 @@ if __name__ == '__main__': log_level = 20 vsetup_logging(LOG, log_level) try: - l = iMain() + l = iMain([]) if l: print(l) i = 0 except KeyboardInterrupt as e: diff --git a/src/stem_examples/relay_connections.py b/src/stem_examples/relay_connections.py index 087cd4a..5c2e3b5 100755 --- a/src/stem_examples/relay_connections.py +++ b/src/stem_examples/relay_connections.py @@ -21,14 +21,14 @@ import stem.connection import stem.util.system import stem.util.str_tools -from stem.control import Listener -from stem.control import Controller +from stem.control import Listener, Controller from stem.util.connection import get_connections, port_usage, is_valid_ipv4_address from stem_examples.tor_controller import get_controller -global LOG import logging +global LOG +LOG = logging.getLogger() HEADER_LINE = " {version} uptime: {uptime} flags: {flags}\n" @@ -44,109 +44,86 @@ OUTBOUND_EXIT = 'Outbound exit traffic' OUTBOUND_UNKNOWN = 'Outbound uncategorized' def iMain(lArgs=None): - if lArgs is None: - lArgs = sys.argv[1:] + if lArgs is None: + lArgs = sys.argv[1:] - parser = argparse.ArgumentParser() - parser.add_argument("--ctrlport", default=9051, type=int, help="default: 9051") - parser.add_argument("--resolver", help="default: autodetected") - args = parser.parse_args(lArgs) + parser = argparse.ArgumentParser() + parser.add_argument("--ctrlport", default=9051, type=int, help="default: 9051") + parser.add_argument("--resolver", help="default: autodetected") + args = parser.parse_args(lArgs) - password = os.environ.get('TOR_CONTROLLER_PASSWORD') - control_port = int(args.ctrlport) if args.ctrlport else 'default' - if False and os.path.exists('/run/tor/control'): - controller = get_controller(password=password, unix='/run/tor/control') - else: - controller = get_controller(password=password, port=control_port) - - if not controller: - return 1 - - desc = controller.get_network_status(default=None) - pid = controller.get_pid() - version = str(controller.get_version()).split()[0], - uptime = stem.util.str_tools.short_time_label(time.time() - stem.util.system.start_time(pid)) - - LOG.info(HEADER_LINE.format( - version=version, - uptime=uptime, - flags = ', '.join(desc.flags if desc else ['none']), - )) - - policy = controller.get_exit_policy() - relays = {} # address => [orports...] - - for desc in controller.get_network_statuses(): - relays.setdefault(desc.address, []).append(desc.or_port) - - # categorize our connections - - categories = collections.OrderedDict(( - (INBOUND_ORPORT, []), - (INBOUND_DIRPORT, []), - (INBOUND_CONTROLPORT, []), - (OUTBOUND_ORPORT, []), - (OUTBOUND_EXIT, []), - (OUTBOUND_UNKNOWN, []), - )) - - exit_connections = {} # port => [connections] - - for conn in get_connections(resolver = args.resolver, process_pid = pid): - if conn.protocol == 'udp': - continue - - if conn.local_port in controller.get_ports(Listener.OR, []): - categories[INBOUND_ORPORT].append(conn) - elif conn.local_port in controller.get_ports(Listener.DIR, []): - categories[INBOUND_DIRPORT].append(conn) - elif conn.local_port in controller.get_ports(Listener.CONTROL, []): - categories[INBOUND_CONTROLPORT].append(conn) - elif conn.remote_port in relays.get(conn.remote_address, []): - categories[OUTBOUND_ORPORT].append(conn) - elif policy.can_exit_to(conn.remote_address, conn.remote_port): - categories[OUTBOUND_EXIT].append(conn) - exit_connections.setdefault(conn.remote_port, []).append(conn) + password = os.environ.get('TOR_CONTROLLER_PASSWORD') + control_port = int(args.ctrlport) if args.ctrlport else 'default' + if False and os.path.exists('/run/tor/control'): + controller = get_controller(password=password, unix='/run/tor/control') else: - categories[OUTBOUND_UNKNOWN].append(conn) + controller = get_controller(password=password, port=control_port) - print(DIV) - print(COLUMN % ('Type', 'IPv4', 'IPv6')) - print(DIV) + if not controller: + return 1 - total_ipv4, total_ipv6 = 0, 0 + desc = controller.get_network_status(default=None) + pid = controller.get_pid() + version = str(controller.get_version()).split()[0], + uptime = stem.util.str_tools.short_time_label(time.time() - stem.util.system.start_time(pid)) - for label, connections in categories.items(): - if len(connections) == 0: - continue + LOG.info(HEADER_LINE.format( + version=version, + uptime=uptime, + flags = ', '.join(desc.flags if desc else ['none']), + )) - ipv4_count = len([conn for conn in connections if is_valid_ipv4_address(conn.remote_address)]) - ipv6_count = len(connections) - ipv4_count + policy = controller.get_exit_policy() + relays = {} # address => [orports...] - total_ipv4, total_ipv6 = total_ipv4 + ipv4_count, total_ipv6 + ipv6_count - print(COLUMN % (label, ipv4_count, ipv6_count)) + for desc in controller.get_network_statuses(): + relays.setdefault(desc.address, []).append(desc.or_port) - print(DIV) - print(COLUMN % ('Total', total_ipv4, total_ipv6)) - print(DIV) - print('') + # categorize our connections + + categories = collections.OrderedDict(( + (INBOUND_ORPORT, []), + (INBOUND_DIRPORT, []), + (INBOUND_CONTROLPORT, []), + (OUTBOUND_ORPORT, []), + (OUTBOUND_EXIT, []), + (OUTBOUND_UNKNOWN, []), + )) + + exit_connections = {} # port => [connections] + + for conn in get_connections(resolver = args.resolver, process_pid = pid): + if conn.protocol == 'udp': + continue + + if conn.local_port in controller.get_ports(Listener.OR, []): + categories[INBOUND_ORPORT].append(conn) + elif conn.local_port in controller.get_ports(Listener.DIR, []): + categories[INBOUND_DIRPORT].append(conn) + elif conn.local_port in controller.get_ports(Listener.CONTROL, []): + categories[INBOUND_CONTROLPORT].append(conn) + elif conn.remote_port in relays.get(conn.remote_address, []): + categories[OUTBOUND_ORPORT].append(conn) + elif policy.can_exit_to(conn.remote_address, conn.remote_port): + categories[OUTBOUND_EXIT].append(conn) + exit_connections.setdefault(conn.remote_port, []).append(conn) + else: + categories[OUTBOUND_UNKNOWN].append(conn) - if exit_connections: print(DIV) - print(COLUMN % ('Exit Port', 'IPv4', 'IPv6')) + print(COLUMN % ('Type', 'IPv4', 'IPv6')) print(DIV) total_ipv4, total_ipv6 = 0, 0 - for port in sorted(exit_connections): - connections = exit_connections[port] + for label, connections in categories.items(): + if len(connections) == 0: + continue + ipv4_count = len([conn for conn in connections if is_valid_ipv4_address(conn.remote_address)]) ipv6_count = len(connections) - ipv4_count + total_ipv4, total_ipv6 = total_ipv4 + ipv4_count, total_ipv6 + ipv6_count - - usage = port_usage(port) - label = '%s (%s)' % (port, usage) if usage else port - print(COLUMN % (label, ipv4_count, ipv6_count)) print(DIV) @@ -154,6 +131,28 @@ def iMain(lArgs=None): print(DIV) print('') + if exit_connections: + print(DIV) + print(COLUMN % ('Exit Port', 'IPv4', 'IPv6')) + print(DIV) + + total_ipv4, total_ipv6 = 0, 0 + + for port in sorted(exit_connections): + connections = exit_connections[port] + ipv4_count = len([conn for conn in connections if is_valid_ipv4_address(conn.remote_address)]) + ipv6_count = len(connections) - ipv4_count + total_ipv4, total_ipv6 = total_ipv4 + ipv4_count, total_ipv6 + ipv6_count + + usage = port_usage(port) + label = '%s (%s)' % (port, usage) if usage else port + + print(COLUMN % (label, ipv4_count, ipv6_count)) + + print(DIV) + print(COLUMN % ('Total', total_ipv4, total_ipv6)) + print(DIV) + print('') if __name__ == '__main__': from stem_examples.stem_utils import vsetup_logging @@ -165,7 +164,7 @@ if __name__ == '__main__': vsetup_logging(LOG, log_level) LOG.setLevel(logging.DEBUG) try: - l = iMain() + l = iMain([]) if l: print(l) i = 0 except KeyboardInterrupt as e: diff --git a/src/stem_examples/tor_bootstrap_check.py b/src/stem_examples/tor_bootstrap_check.py index 50f0898..d54a904 100755 --- a/src/stem_examples/tor_bootstrap_check.py +++ b/src/stem_examples/tor_bootstrap_check.py @@ -60,9 +60,8 @@ if __name__ == '__main__': else: log_level = 20 vsetup_logging(LOG, log_level) - LOG.setLevel(logging.DEBUG) try: - i = iMain() + i = iMain([]) except KeyboardInterrupt as e: i = 0 except Exception as e: diff --git a/stem_examples.txt b/stem_examples.txt index 8fc33ca..b0611c8 100644 --- a/stem_examples.txt +++ b/stem_examples.txt @@ -54,20 +54,21 @@ If you don't have one, make it with the settings from your torrc: >>> print("yaml", file=sys.stderr) >>> import yaml >>> try: - ... sFacts = open('/usr/local/etc/testforge/testforge.yml').read() + ... sFacts = open('/usr/local/etc/testforge/testforge.yml').read() + ... assert sFacts, sFacts ... except: - ... dFacts = { - ... HTTPS_PROXYHOST: "127.0.0.1", - ... HTTPS_PROXYPORT: 9128, - ... HTTPS_PROXYTYPE: "http", - ... SOCKS_PROXYHOST: "127.0.0.1", - ... SOCKS_PROXYPORT: 9050, - ... SOCKS_PROXYTYPE: "socks5", - ... } + ... dFacts = dict( + ... HTTPS_PROXYHOST="127.0.0.1", + ... HTTPS_PROXYPORT=9128, + ... HTTPS_PROXYTYPE="http", + ... SOCKS_PROXYHOST="127.0.0.1", + ... SOCKS_PROXYPORT=9050, + ... SOCKS_PROXYTYPE="socks5", + ... ) ... else: - ... assert sFacts - ... dFacts = yaml.safe_load(sFacts) + ... dFacts = yaml.safe_load(sFacts) + FixMe: use the settings for the ports and directories below. >>> import os @@ -94,7 +95,7 @@ and then the descriptor-signing-key-cert: >>> introduction_points.iMain(lKNOWN_ONIONS) #doctest: +ELLIPSIS +NORMALIZE_WHITESPACE 0 -hs-descriptor 3 + hs-descriptor 3 descriptor-lifetime ... @@ -106,11 +107,17 @@ How can you figure out what exit you're using? >>> print("exit_used", file=sys.stderr) >>> import exit_used + >>> exit_used.iMain([]) ## relay_connections Connection Summary >>> print("relay_connections", file=sys.stderr) >>> import relay_connections + >>> relay_connections.iMain([]) #doctest: +ELLIPSIS +NORMALIZE_WHITESPACE + +------------------------------+------+------+ + ... + +------------------------------+------+------+ + The following provides a summary of your relay's inbound and outbound connections. You must be root or tor to run this: @@ -124,25 +131,22 @@ provides an easy method for accessing this information. >>> print("connection_resolution", file=sys.stderr) >>> import connection_resolution - >>> connection_resolution.iMain() #doctest: +ELLIPSIS +NORMALIZE_WHITESPACE + >>> connection_resolution.iMain([]) #doctest: +ELLIPSIS +NORMALIZE_WHITESPACE 0 INFO Our platform supports connection resolution via: ... -## outdated_relays List Outdated Relays +## interpreter -Time marches on. Tor makes new releases, and at some point needs to drop -support for old ones. Below is the script we used on ticket 9476 to reach out -to relay operators that needed to upgrade. - - >>> print("outdated_relays", file=sys.stderr) - >>> import outdated_relays - >>> outdated_relays.iMain() #doctest: +ELLIPSIS +NORMALIZE_WHITESPACE - 0 - - Checking for outdated relays ... + >>> print("interpreter", file=sys.stderr) + >>> import interpreter + >>> lArgs = ['GETINFO', 'version'] + >>> interpreter.iMain(lArgs) #doctest: +ELLIPSIS +NORMALIZE_WHITESPACE + 250-version=0.4.8.10 + 250 OK + 0 ## tor_bootstrap_check @@ -152,9 +156,35 @@ to relay operators that needed to upgrade. A script by adrelanos@riseup.net to check what percentage of boostrapping tor is at. This fails under doctest but not from the cmdline - >>> tor_bootstrap_check.iMain() #doctest: +ELLIPSIS +NORMALIZE_WHITESPACE + >>> tor_bootstrap_check.iMain([]) #doctest: +ELLIPSIS +NORMALIZE_WHITESPACE 0 NOTICE ... +## check_digests + + >>> print("check_digests", file=sys.stderr) + >>> from support_testing import ignoreStdout + >>> from check_digests import iMain + >>> sKNOWN_ONION = 'facebookwkhpilnemxj7asaniu7vnjjbiltxjqhye3mhbshg7kx5tfyd' # facebook + >>> from stem_examples.introduction_points import lMain as lIPMain + >>> with ignoreStdout(): + ... lArgs = lIPMain([sKNOWN_ONION]) + >>> iMain(lArgs) + 0 + +## outdated_relays List Outdated Relays + +Time marches on. Tor makes new releases, and at some point needs to drop +support for old ones. Below is the script we used on ticket 9476 to reach out +to relay operators that needed to upgrade. + + >>> print("outdated_relays", file=sys.stderr) + >>> import outdated_relays + >>> outdated_relays.iMain([]) #doctest: +ELLIPSIS +NORMALIZE_WHITESPACE + 0 + + Checking for outdated relays ... + +