commit 843facd89a35658a750dddfba86d0dfcddd6fe69 Author: Damian Johnson atagar@torproject.org Date: Fri Dec 22 12:21:35 2017 -0800
Add demo for getting a relay conneciton summary
Revising a neat stem script by toralf that provides a summary of your relay's connections. --- docs/_static/example/load_test.py | 25 +++++ docs/_static/example/relay_connections.py | 129 ++++++++++++++++++++++ docs/change_log.rst | 6 + docs/contents.rst | 1 + docs/tutorials/double_double_toil_and_trouble.rst | 8 ++ docs/tutorials/examples/relay_connections.rst | 48 ++++++++ 6 files changed, 217 insertions(+)
diff --git a/docs/_static/example/load_test.py b/docs/_static/example/load_test.py new file mode 100644 index 00000000..e98e4c00 --- /dev/null +++ b/docs/_static/example/load_test.py @@ -0,0 +1,25 @@ +import os +import time + +import stem.control +import stem.util.proc +import stem.util.str_tools + +start_time = time.time() +samplings = [] +last_sample = None + +with stem.control.Controller.from_port() as controller: + controller.authenticate() + controller.add_event_listener(lambda *args: None, 'DEBUG') + + while True: + utime, stime = stem.util.proc.stats(os.getpid(), stem.util.proc.Stat.CPU_UTIME, stem.util.proc.Stat.CPU_STIME) + total_cpu_time = float(utime) + float(stime) + + if last_sample: + samplings.append(total_cpu_time - last_sample) + print '%0.1f%% (%s)' % (sum(samplings) / len(samplings) * 100, stem.util.str_tools.time_label(time.time() - start_time)) + + last_sample = total_cpu_time + time.sleep(1) diff --git a/docs/_static/example/relay_connections.py b/docs/_static/example/relay_connections.py new file mode 100755 index 00000000..42c22fa5 --- /dev/null +++ b/docs/_static/example/relay_connections.py @@ -0,0 +1,129 @@ +import argparse +import collections +import time + +import stem.connection +import stem.util.system +import stem.util.str_tools + +from stem.control import Listener +from stem.util.connection import get_connections, port_usage, is_valid_ipv4_address + +HEADER_LINE = " {version} uptime: {uptime} flags: {flags}\n" + +DIV = '+%s+%s+%s+' % ('-' * 30, '-' * 6, '-' * 6) +COLUMN = '| %-28s | %4s | %4s |' + +INBOUND_ORPORT = 'Inbound to our ORPort' +INBOUND_DIRPORT = 'Inbound to our DirPort' +INBOUND_CONTROLPORT = 'Inbound to our ControlPort' + +OUTBOUND_ORPORT = 'Outbound to a relay' +OUTBOUND_EXIT = 'Outbound exit traffic' +OUTBOUND_UNKNOWN = 'Outbound uncategorized' + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("--ctrlport", help="default: 9051 or 9151") + parser.add_argument("--resolver", help="default: autodetected") + args = parser.parse_args() + + control_port = int(args.ctrlport) if args.ctrlport else 'default' + controller = stem.connection.connect(control_port = ('127.0.0.1', control_port)) + + if not controller: + return + + desc = controller.get_network_status(default = None) + pid = controller.get_pid() + + print(HEADER_LINE.format( + version = str(controller.get_version()).split()[0], + uptime = stem.util.str_tools.short_time_label(time.time() - stem.util.system.start_time(pid)), + 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 + + connections = 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, []): + connections[INBOUND_ORPORT].append(conn) + elif conn.local_port in controller.get_ports(Listener.DIR, []): + connections[INBOUND_DIRPORT].append(conn) + elif conn.local_port in controller.get_ports(Listener.CONTROL, []): + connections[INBOUND_CONTROLPORT].append(conn) + elif conn.remote_port in relays.get(conn.remote_address, []): + connections[OUTBOUND_ORPORT].append(conn) + elif policy.can_exit_to(conn.remote_address, conn.remote_port): + connections[OUTBOUND_EXIT].append(conn) + exit_connections.setdefault(conn.remote_port, []).append(conn) + else: + connections[OUTBOUND_UNKNOWN].append(conn) + + print(DIV) + print(COLUMN % ('Type', 'IPv4', 'IPv6')) + print(DIV) + + total_ipv4, total_ipv6 = 0, 0 + + for label, connections in connections.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 + print(COLUMN % (label, ipv4_count, ipv6_count)) + + print(DIV) + print(COLUMN % ('Total', total_ipv4, total_ipv6)) + 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): + ipv4_count = len([conn for conn in connections if is_valid_ipv4_address(conn.remote_address)]) + ipv6_count = len(exit_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__': + main() diff --git a/docs/change_log.rst b/docs/change_log.rst index 13597155..3985dfcb 100644 --- a/docs/change_log.rst +++ b/docs/change_log.rst @@ -49,6 +49,12 @@ The following are only available within Stem's `git repository * Added support for limiting the maximum number of streams to :func:`~stem.control.Controller.create_ephemeral_hidden_service` (:spec:`2fcb1c2`) * Stacktrace if :func:`stem.connection.connect` had a string port argument
+ * **Website** + + * Added `terminal styling <tutorials/east_of_the_sun.html#terminal-styling>`_ to our utilities tutorial + * Added `multiprocessing <tutorials/east_of_the_sun.html#multiprocessing>`_ to our utilities tutorial + * Added a `relay connection summary example <tutorials/examples/relay_connections.html>`_ + .. _version_1.6:
Version 1.6 (November 5th, 2017) diff --git a/docs/contents.rst b/docs/contents.rst index 5cbd5bf2..c9c38ebf 100644 --- a/docs/contents.rst +++ b/docs/contents.rst @@ -17,6 +17,7 @@ Contents tutorials/examples/compare_flags tutorials/examples/exit_used tutorials/examples/list_circuits + tutorials/examples/relay_connections tutorials/examples/outdated_relays tutorials/examples/persisting_a_consensus tutorials/examples/votes_by_bandwidth_authorities diff --git a/docs/tutorials/double_double_toil_and_trouble.rst b/docs/tutorials/double_double_toil_and_trouble.rst index 111952c6..48d665aa 100644 --- a/docs/tutorials/double_double_toil_and_trouble.rst +++ b/docs/tutorials/double_double_toil_and_trouble.rst @@ -99,6 +99,14 @@ Client Usage
Tells you the exit used for each Tor connection.
+Relays +------ + +* `Connection Summary <examples/relay_connections.html>`_ + + Provides a summary of your inbound and outbound connections and exiting + usage. + Descriptors -----------
diff --git a/docs/tutorials/examples/relay_connections.rst b/docs/tutorials/examples/relay_connections.rst new file mode 100644 index 00000000..c389f9aa --- /dev/null +++ b/docs/tutorials/examples/relay_connections.rst @@ -0,0 +1,48 @@ +Connection Summary +================== + +.. image:: /_static/buttons/back.png + :target: ../double_double_toil_and_trouble.html + +The following provides a summary of your relay's inbound and outbound +connections. Couple important notes... + + * To use this you must set **DisableDebuggerAttachment 0** in your torrc. + Otherwise connection information will be unavailable. + + * **Be careful about the data you look at.** Inspection of client and exit + traffic especially is wiretapping and not only unethical but likely + illegal. + + That said, a general overview like this should be fine. + +.. literalinclude:: /_static/example/relay_connections.py + :language: python + +:: + + % relay_connections.py --ctrlport 29051 + + 0.3.2.0-alpha-dev uptime: 01:20:44 flags: none + + +------------------------------+------+------+ + | Type | IPv4 | IPv6 | + +------------------------------+------+------+ + | Inbound to our ORPort | 2400 | 3 | + | Inbound to our DirPort | 12 | 0 | + | Inbound to our ControlPort | 2 | 0 | + | Outbound to a relay | 324 | 0 | + | Outbound exit traffic | 3 | 0 | + +------------------------------+------+------+ + | Total | 2741 | 3 | + +------------------------------+------+------+ + + +------------------------------+------+------+ + | Exit Port | IPv4 | IPv6 | + +------------------------------+------+------+ + | 443 (HTTPS) | 1 | 0 | + | 8443 (PCsync HTTPS) | 1 | 0 | + | 54682 | 1 | 0 | + +------------------------------+------+------+ + | Total | 3 | 0 | + +------------------------------+------+------+