From 81b50a22f45f7d28dc448e92aa6459992c1d9bb3 Mon Sep 17 00:00:00 2001 From: Matt Traudt <sirmatt@ksu.edu> Date: Sat, 24 Mar 2018 08:28:33 -0400 Subject: [PATCH] Turn into a package Hopefully everything works first try --- .gitignore | 1 + requirements.txt | 2 - {lib => sbws}/__init__.py | 0 sbws/__main__.py | 35 +++++++++ {util => sbws/commands}/__init__.py | 0 scanner.py => sbws/commands/client.py | 100 +++++++++++++------------- server.py => sbws/commands/server.py | 48 ++++++------- sbws/lib/__init__.py | 0 {lib => sbws/lib}/circuitbuilder.py | 4 +- {lib => sbws/lib}/pastlylogger.py | 0 {lib => sbws/lib}/periodicevent.py | 0 {lib => sbws/lib}/relaylist.py | 2 +- {lib => sbws/lib}/resultdump.py | 0 sbws/util/__init__.py | 0 {util => sbws/util}/simpleauth.py | 0 {util => sbws/util}/stem.py | 0 setup.py | 72 +++++++++++++++++++ 17 files changed, 184 insertions(+), 80 deletions(-) delete mode 100644 requirements.txt rename {lib => sbws}/__init__.py (100%) create mode 100644 sbws/__main__.py rename {util => sbws/commands}/__init__.py (100%) rename scanner.py => sbws/commands/client.py (79%) mode change 100755 => 100644 rename server.py => sbws/commands/server.py (79%) mode change 100755 => 100644 create mode 100644 sbws/lib/__init__.py rename {lib => sbws/lib}/circuitbuilder.py (99%) rename {lib => sbws/lib}/pastlylogger.py (100%) rename {lib => sbws/lib}/periodicevent.py (100%) rename {lib => sbws/lib}/relaylist.py (98%) rename {lib => sbws/lib}/resultdump.py (100%) create mode 100644 sbws/util/__init__.py rename {util => sbws/util}/simpleauth.py (100%) rename {util => sbws/util}/stem.py (100%) create mode 100755 setup.py diff --git a/.gitignore b/.gitignore index bbfe4321..8d245e55 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ __pycache__ venv passwords.txt +*.egg-info diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 1b85859a..00000000 --- a/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -PySocks==1.6.8 -stem==1.6.0 diff --git a/lib/__init__.py b/sbws/__init__.py similarity index 100% rename from lib/__init__.py rename to sbws/__init__.py diff --git a/sbws/__main__.py b/sbws/__main__.py new file mode 100644 index 00000000..6a081fb8 --- /dev/null +++ b/sbws/__main__.py @@ -0,0 +1,35 @@ +import sbws.commands.client +import sbws.commands.server +from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter + + +VERSION = '0.0.1' + + +def create_parser(): + p = ArgumentParser(formatter_class=ArgumentDefaultsHelpFormatter) + sub = p.add_subparsers(dest='command') + sbws.commands.client.gen_parser(sub) + sbws.commands.server.gen_parser(sub) + return p + + +def main(): + parser = create_parser() + args = parser.parse_args() + def_args = [args] + def_kwargs = {} + known_commands = { + 'client': {'f': sbws.commands.client.main, + 'a': def_args, 'kw': def_kwargs}, + 'server': {'f': sbws.commands.server.main, + 'a': def_args, 'kw': def_kwargs}, + } + try: + if args.command not in known_commands: + parser.print_help() + else: + comm = known_commands[args.command] + exit(comm['f'](*comm['a'], **comm['kw'])) + except KeyboardInterrupt: + print('') diff --git a/util/__init__.py b/sbws/commands/__init__.py similarity index 100% rename from util/__init__.py rename to sbws/commands/__init__.py diff --git a/scanner.py b/sbws/commands/client.py old mode 100755 new mode 100644 similarity index 79% rename from scanner.py rename to sbws/commands/client.py index 9734148d..0480b2dd --- a/scanner.py +++ b/sbws/commands/client.py @@ -1,27 +1,26 @@ -#!/usr/bin/env python3 -from argparse import ArgumentDefaultsHelpFormatter, ArgumentParser -import time -import socks # PySocks -import socket -import random +from ..lib.pastlylogger import PastlyLogger +from ..lib.circuitbuilder import GapsCircuitBuilder as CB +from ..lib.resultdump import ResultDump +from ..lib.resultdump import Result +from ..lib.relaylist import RelayList +from ..util.simpleauth import is_good_clientside_password_file +from ..util.simpleauth import authenticate_to_server +import sbws.util.stem as stem_utils from stem.control import EventType +from argparse import ArgumentDefaultsHelpFormatter +from multiprocessing.dummy import Pool from threading import Event from threading import RLock -from multiprocessing.dummy import Pool -import util.stem as stem_utils -from util.simpleauth import is_good_clientside_password_file -from util.simpleauth import authenticate_to_server -from lib.circuitbuilder import GapsCircuitBuilder as CB -from lib.resultdump import ResultDump -from lib.resultdump import Result -from lib.relaylist import RelayList -from lib.pastlylogger import PastlyLogger +import random +import socks +import socket +import time + +log = None end_event = Event() stream_building_lock = RLock() -log = PastlyLogger(debug='/dev/stdout', overwrite=['debug'], log_threads=True) -# maximum we want to read per read() call MAX_RECV_PER_READ = 1*1024*1024 DOWNLOAD_TIMES = {'toofast': 1, 'min': 5, 'target': 6, 'max': 10} DESIRED_RESULTS = 5 @@ -227,7 +226,7 @@ def test_speedtest(args): pending_results = [] relays = rl.relays random.shuffle(relays) - for target in relays: + for target in relays[0:2]: callback = result_putter(rd) callback_err = result_putter_error(target) async_result = pool.apply_async( @@ -243,37 +242,38 @@ def test_speedtest(args): log.notice('Got all results') +def gen_parser(sub): + p = sub.add_parser('client', + formatter_class=ArgumentDefaultsHelpFormatter) + p.add_argument('--control', nargs=2, metavar=('TYPE', 'LOCATION'), + default=['port', '9051'], + help='How to control Tor. Examples: "port 9051" or ' + '"socket /var/lib/tor/control"') + p.add_argument('--socks-host', default='127.0.0.1', type=str, + help='Host for a local Tor SocksPort') + p.add_argument('--socks-port', default=9050, type=int, + help='Port for a local Tor SocksPort') + p.add_argument('--server-host', default='127.0.0.1', type=str, + help='Host for a measurement server') + p.add_argument('--server-port', default=4444, type=int, + help='Port for a measurement server') + p.add_argument('--result-directory', default='dd', type=str, + help='Where to store raw result output') + p.add_argument('--threads', default=1, type=int, + help='Number of measurements to make in parallel') + p.add_argument('--helper-relay', type=str, required=True, + help='Relay to which to build circuits and is running ' + 'the server.py') + p.add_argument('--password-file', type=str, default='passwords.txt', + help='Read the first line and use it as the password ' + 'when authenticating to the server.') + + def main(args): - test_speedtest(args) - - -if __name__ == '__main__': - parser = ArgumentParser( - formatter_class=ArgumentDefaultsHelpFormatter) - parser.add_argument('--control', nargs=2, metavar=('TYPE', 'LOCATION'), - default=['port', '9051'], - help='How to control Tor. Examples: "port 9051" or ' - '"socket /var/lib/tor/control"') - parser.add_argument('--socks-host', default='127.0.0.1', type=str, - help='Host for a local Tor SocksPort') - parser.add_argument('--socks-port', default=9050, type=int, - help='Port for a local Tor SocksPort') - parser.add_argument('--server-host', default='127.0.0.1', type=str, - help='Host for a measurement server') - parser.add_argument('--server-port', default=4444, type=int, - help='Port for a measurement server') - parser.add_argument('--result-directory', default='dd', type=str, - help='Where to store raw result output') - parser.add_argument('--threads', default=1, type=int, - help='Number of measurements to make in parallel') - parser.add_argument('--helper-relay', type=str, required=True, - help='Relay to which to build circuits and is running ' - 'the server.py') - parser.add_argument('--password-file', type=str, default='passwords.txt', - help='Read the first line and use it as the password ' - 'when authenticating to the server.') - - args = parser.parse_args() + global log + log = PastlyLogger(debug='/dev/stdout', overwrite=['debug'], + log_threads=True) + if args.threads < 1: fail_hard('--threads must be larger than 1') @@ -289,10 +289,8 @@ if __name__ == '__main__': fail_hard(error_reason) try: - main(args) + test_speedtest(args) except KeyboardInterrupt as e: raise e finally: end_event.set() - -# pylama:ignore=E265 diff --git a/server.py b/sbws/commands/server.py old mode 100755 new mode 100644 similarity index 79% rename from server.py rename to sbws/commands/server.py index 69fab361..7405731c --- a/server.py +++ b/sbws/commands/server.py @@ -1,18 +1,28 @@ -#!/usr/bin/env python3 -from argparse import ArgumentDefaultsHelpFormatter, ArgumentParser +from ..lib.pastlylogger import PastlyLogger +from ..util.simpleauth import authenticate_client +from ..util.simpleauth import is_good_serverside_password_file +from argparse import ArgumentDefaultsHelpFormatter +from threading import Thread import socket import time -from threading import Thread -from lib.pastlylogger import PastlyLogger -from util.simpleauth import authenticate_client -from util.simpleauth import is_good_serverside_password_file -log = PastlyLogger(debug='/dev/stdout', overwrite=['debug'], log_threads=True) + +log = None MAX_SEND_PER_WRITE = 100*1024*1024 MAX_SEND_PER_WRITE = 4096 +def gen_parser(sub): + p = sub.add_parser('server', + formatter_class=ArgumentDefaultsHelpFormatter) + p.add_argument('bind_ip', type=str, default='127.0.0.1') + p.add_argument('bind_port', type=int, default=4444) + p.add_argument('--password-file', type=str, default='passwords.txt', + help='All lines in this file will be considered ' + 'valid passwords scanners may use to authenticate.') + + def fail_hard(*s): ''' Optionally log something to stdout ... and then exit as fast as possible ''' @@ -95,6 +105,13 @@ def new_thread(args, sock): def main(args): + global log + log = PastlyLogger(debug='/dev/stdout', overwrite=['debug'], + log_threads=True) + valid, error_reason = is_good_serverside_password_file(args.password_file) + if not valid: + fail_hard(error_reason) + server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) h = (args.bind_ip, args.bind_port) log.notice('binding to', h) @@ -118,20 +135,3 @@ def main(args): pass finally: close_socket(server) - - -if __name__ == '__main__': - parser = ArgumentParser( - formatter_class=ArgumentDefaultsHelpFormatter) - parser.add_argument('bind_ip', type=str, default='127.0.0.1') - parser.add_argument('bind_port', type=int, default=4444) - parser.add_argument('--password-file', type=str, default='passwords.txt', - help='All lines in this file will be considered ' - 'valid passwords scanners may use to authenticate.') - args = parser.parse_args() - - valid, error_reason = is_good_serverside_password_file(args.password_file) - if not valid: - fail_hard(error_reason) - - main(args) diff --git a/sbws/lib/__init__.py b/sbws/lib/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/lib/circuitbuilder.py b/sbws/lib/circuitbuilder.py similarity index 99% rename from lib/circuitbuilder.py rename to sbws/lib/circuitbuilder.py index a370180a..2a446c49 100644 --- a/lib/circuitbuilder.py +++ b/sbws/lib/circuitbuilder.py @@ -1,7 +1,7 @@ from stem import (CircuitExtensionFailed, InvalidRequest) import random -import util.stem as stem_utils -from lib.relaylist import RelayList +import sbws.util.stem as stem_utils +from .relaylist import RelayList class PathLengthException(Exception): diff --git a/lib/pastlylogger.py b/sbws/lib/pastlylogger.py similarity index 100% rename from lib/pastlylogger.py rename to sbws/lib/pastlylogger.py diff --git a/lib/periodicevent.py b/sbws/lib/periodicevent.py similarity index 100% rename from lib/periodicevent.py rename to sbws/lib/periodicevent.py diff --git a/lib/relaylist.py b/sbws/lib/relaylist.py similarity index 98% rename from lib/relaylist.py rename to sbws/lib/relaylist.py index 97b93f49..8b5eacf3 100644 --- a/lib/relaylist.py +++ b/sbws/lib/relaylist.py @@ -1,4 +1,4 @@ -import util.stem as stem_utils +import sbws.util.stem as stem_utils from stem import Flag import time import random diff --git a/lib/resultdump.py b/sbws/lib/resultdump.py similarity index 100% rename from lib/resultdump.py rename to sbws/lib/resultdump.py diff --git a/sbws/util/__init__.py b/sbws/util/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/util/simpleauth.py b/sbws/util/simpleauth.py similarity index 100% rename from util/simpleauth.py rename to sbws/util/simpleauth.py diff --git a/util/stem.py b/sbws/util/stem.py similarity index 100% rename from util/stem.py rename to sbws/util/stem.py diff --git a/setup.py b/setup.py new file mode 100755 index 00000000..330f9332 --- /dev/null +++ b/setup.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python3 +# Always prefer setuptools over distutils +from setuptools import setup, find_packages +# To use a consistent encoding +from codecs import open +import os +import re + +here = os.path.abspath(os.path.dirname(__file__)) + +with open(os.path.join(here, 'README.md'), encoding='utf-8') as f: + long_description = f.read() + + +def get_package_data(): + # Example that grabs all *.ini files in the cwd and all files in foo/bar + # other_files = ['*.ini'] + # for r, _, fs in os.walk(os.path.join(here, 'foo', 'bar')): + # for f in fs: + # other_files.append(os.path.join(r, f)) + # return other_files + return [] + + +def find_version(fname): + with open(fname, 'rt') as fd: + contents = fd.read() + match = re.search(r"^VERSION = ['\"]([^'\"]*)['\"]", contents, re.M) + if match: + return match.group(1) + raise RuntimeError('Unable to find version string') + + +setup( + name='sbws', + version=find_version('sbws/__main__.py'), + description='Simple Bandwidth Scanner', + long_description=long_description, + author='Matt Traudt', + author_email='pastly@torproject.org', + # license='MIT', + # https://packaging.python.org/tutorials/distributing-packages/#id48 + # https://pypi.python.org/pypi?%3Aaction=list_classifiers + classifiers=[ + # How mature is this project? Common values are + # 3 - Alpha + # 4 - Beta + # 5 - Production/Stable + 'Development Status :: 3 - Alpha', + ], + packages=find_packages(), + # package_data={ + # 'foo': get_package_data(), + # }, + keywords='', + python_requires='>=3.5', + # test_suite='test', + entry_points={ + 'console_scripts': [ + 'sbws = sbws.__main__:main', + ] + }, + install_requires=[ + 'stem', + 'pysocks', + ], + extras_require={ + 'dev': [], + 'test': [], + 'doc': ['sphinx'], + }, +) -- GitLab