Skip to content
This repository was archived by the owner on Mar 2, 2022. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1 +1 @@
include README LICENSE requirements.txt
include README.rst requirements.txt bwscanner/data/config.ini
46 changes: 46 additions & 0 deletions bwscanner/configutil.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import os.path
from ConfigParser import SafeConfigParser
from pkg_resources import resource_string

from bwscanner.logger import log


def read_config(cfg_path):
log.debug('Reading config %s' % cfg_path)
if not config_exists(cfg_path):
copy_config(cfg_path)
parser = SafeConfigParser()
parser.read([cfg_path])
cfg_dict = dict(parser.items('default'))
int_keys = cfg_dict['int_keys'].split(' ')
bool_keys = cfg_dict['bool_keys'].split(' ')
for k in int_keys:
cfg_dict[k] = int(cfg_dict[k])
for i in bool_keys:
cfg_dict[k] = bool(cfg_dict[k])
bw_files = dict(parser.items('bw_files'))
cfg_bw_files = {}
for k, v in bw_files.items():
print(k, v)
if 'm' in k:
number = k.rstrip('m')
size = 1024 * int(number)
cfg_bw_files[size] = (k.upper(), v)
cfg_dict['bw_files'] = cfg_bw_files
return cfg_dict


def config_exists(cfg_path):
return os.path.isfile(cfg_path)


def copy_config(cfg_path, cfg_default_path=None):
# FIXME: obtain the path instead of the content
if cfg_default_path is None:
content = resource_string(__name__, 'data/config.ini')
else:
with open(cfg_default_path) as fp:
content = cfg_default_path.read()
log.debug("cfg_default_path %s" % cfg_default_path)
with open(cfg_path, 'w') as fp:
fp.write(content)
25 changes: 25 additions & 0 deletions bwscanner/data/config.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
[default]

data_dir = ~/.config/bwscanner
measurement_dir = ~/.config/bwscanner/measurements
tor_dir = ~/.config/bwscanner/tordata
loglevel = info
logfile = bwscanner.log
baseurl = https://siv.sunet.se/bwauth/
launch_tor = True
circuit_build_timeout = 20
partitions = 1
current_partition = 1
timeout = 120
request_limit = 10
int_keys = partitions current_partition timeout request_limit
bool_keys = launch_tor

[bw_files]

64M = 6258de4f4d602be75a3458117b29d2c580c4bcb7ba5b9d2c4135c7603109f554
32M = 5a5d66d7865f09498d776f20c9e9791b055a4fff357185f84fb4ecfca7da93f0
16M = 6258de4f4d602be75a3458117b29d2c580c4bcb7ba5b9d2c4135c7603109f554
8M = 738c5604295b9377f7636ce0c2c116f093bb50372f589a6c2332a3bb6bba096a
4M = 4daaa42377d3c87577797d44a8fa569038e7a9d6a5d417a09d8ba41a69456164
2M = 3e39b0bb92912cf1ad6c01fb7c9d592e814a691c61de1f649416f6bba2d15082
50 changes: 36 additions & 14 deletions bwscanner/scanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,30 @@
from twisted.internet import reactor

from bwscanner.attacher import connect_to_tor
from bwscanner.configutil import read_config
from bwscanner.logger import setup_logging, log
from bwscanner.measurement import BwScan
from bwscanner.aggregate import write_aggregate_data


BWSCAN_VERSION = '0.0.1'
APP_NAME = 'bwscanner'
DATA_DIR = os.environ.get("BWSCANNER_DATADIR", click.get_app_dir(APP_NAME))
CONFIG_FILE = 'config.ini'
LOG_FILE = 'bwscanner.log'


class ScanInstance(object):
"""
Store the configuration and state for the CLI tool.
"""
def __init__(self, data_dir):
def __init__(self, data_dir, measurement_dir=None):
self.data_dir = data_dir
self.measurement_dir = os.path.join(data_dir, 'measurements')
self.tor_dir = os.path.join(data_dir, 'tor_data')
if measurement_dir is None:
self.measurement_dir = os.path.join(data_dir, 'measurements')
else:
self.measurement_dir = measurement_dir
self.tor_state = None

def __repr__(self):
return '<BWScan %r>' % self.data_dir
Expand All @@ -30,18 +38,22 @@ def __repr__(self):
pass_scan = click.make_pass_decorator(ScanInstance)


# FIXME: check these errors
# pylint: disable=unexpected-keyword-arg
# pylint: disable=no-value-for-parameter
@click.group()
@click.option('--data-dir', type=click.Path(),
default=os.environ.get("BWSCANNER_DATADIR", click.get_app_dir('bwscanner')),
help='Directory where bwscan should stores its measurements and '
'other data.')
@click.option('-l', '--loglevel', help='The logging level the scanner will use (default: info)',
default='info', type=click.Choice(['debug', 'info', 'warn', 'error', 'critical']))
@click.option('-f', '--logfile', type=click.Path(), help='The file the log will be written to',
default=os.environ.get("BWSCANNER_LOGFILE", 'bwscanner.log'))
@click.option('--launch-tor/--no-launch-tor', default=False,
@click.option('-l', '--loglevel',
help='The logging level the scanner will use (default: info)',
type=click.Choice(
['debug', 'info', 'warn', 'error', 'critical']))
@click.option('-f', '--logfile', type=click.Path(),
help='The file the log will be written to')
@click.option('--launch-tor/--no-launch-tor',
help='Launch Tor or try to connect to an existing Tor instance.')
@click.option('--circuit-build-timeout', default=20,
@click.option('--circuit-build-timeout',
help='Option passed when launching Tor.')
@click.version_option(BWSCAN_VERSION)
@click.pass_context
Expand All @@ -51,9 +63,12 @@ def cli(ctx, data_dir, loglevel, logfile, launch_tor, circuit_build_timeout):
bandwidth measurements can then be aggregate to create the bandwidth
values used by the Tor bandwidth authorities when creating the Tor consensus.
"""
for k, v in ctx.default_map.items():
if ctx.params.get(k) is None:
ctx.params[k] = v

# Create the data directory if it doesn't exist
data_dir = os.path.abspath(data_dir)
ctx.obj = ScanInstance(data_dir)
ctx.obj = ScanInstance(ctx.params.get('data_dir'))

if not os.path.isdir(ctx.obj.measurement_dir):
os.makedirs(ctx.obj.measurement_dir)
Expand All @@ -63,7 +78,8 @@ def cli(ctx, data_dir, loglevel, logfile, launch_tor, circuit_build_timeout):
ctx.obj.tor_dir)

# Set up the logger to only output log lines of level `loglevel` and above.
setup_logging(log_level=loglevel, log_name=logfile)
setup_logging(log_level=ctx.params.get('loglevel'),
log_name=ctx.params.get('logfile'))


@cli.command(short_help="Measure the Tor relays.")
Expand All @@ -85,7 +101,8 @@ def scan(scan, partitions, current_partition, timeout, request_limit):

# XXX: check that each run is producing the same input set!
scan_time = str(int(time.time()))
scan_data_dir = os.path.join(scan.measurement_dir, '{}.running'.format(scan_time))
scan_data_dir = os.path.join(scan.measurement_dir,
'{}.running'.format(scan_time))
if not os.path.isdir(scan_data_dir):
os.makedirs(scan_data_dir)

Expand Down Expand Up @@ -160,3 +177,8 @@ def aggregate(scan, scan_name, previous):
scan.tor_state.addErrback(lambda failure: log.failure("Unexpected error"))
scan.tor_state.addCallback(lambda _: reactor.stop())
reactor.run()


def start():
config = read_config(os.path.join(DATA_DIR, CONFIG_FILE))
return cli(default_map=config)
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@
},
python_requires=">=2.7",
# data_files = [('path', ['filename'])]
data_files=[],
include_package_data=True,
entry_points={
"console_scripts": [
'bwscan = bwscanner.scanner:cli',
'bwscan = bwscanner.scanner:start',
]},
)