Merge branch 'bug4647_squashed'

This commit is contained in:
Nick Mathewson 2013-09-13 12:36:55 -04:00
commit e35c972851
10 changed files with 495 additions and 89 deletions

18
changes/bug4647 Normal file
View File

@ -0,0 +1,18 @@
o Minor bugfixes:
- Use a single command-line parser for parsing torrc options on the
command line and for finding special command-line options to avoid
inconsistent behavior for torrc option arguments that have the same
names as command-line options. Fixes bugs 4647 and 9578; bugfix on
0.0.9pre5.
- No longer allow 'tor --hash-password' with no arguments. Fixes bug
9573; bugfix on 0.0.9pre5.
o Minor features:
- Support a --dump-config optoin to dump some or all of the configured
options. Mainly useful for debugging the command-line option parsing
code.

View File

@ -46,7 +46,7 @@ COMMAND-LINE OPTIONS
configuration file, and by those on the command line. (Default:
@CONFDIR@/torrc-defaults.)
**--hash-password**::
**--hash-password** __PASSWORD__::
Generates a hashed password for control port access.
**--list-fingerprint**::

View File

@ -550,6 +550,9 @@ static int parse_outbound_addresses(or_options_t *options, int validate_only,
char **msg);
static void config_maybe_load_geoip_files_(const or_options_t *options,
const or_options_t *old_options);
static int options_validate_cb(void *old_options, void *options,
void *default_options,
int from_setconf, char **msg);
/** Magic value for or_options_t. */
#define OR_OPTIONS_MAGIC 9090909
@ -561,7 +564,7 @@ STATIC config_format_t options_format = {
STRUCT_OFFSET(or_options_t, magic_),
option_abbrevs_,
option_vars_,
(validate_fn_t)options_validate,
options_validate_cb,
NULL
};
@ -724,6 +727,7 @@ or_options_free(or_options_t *options)
smartlist_free(options->NodeFamilySets);
}
tor_free(options->BridgePassword_AuthDigest_);
tor_free(options->command_arg);
config_free(&options_format, options);
}
@ -1790,40 +1794,64 @@ options_act(const or_options_t *old_options)
return 0;
}
/** Helper: Read a list of configuration options from the command line.
* If successful, put them in *<b>result</b> and return 0, and return
* -1 and leave *<b>result</b> alone. */
static int
config_get_commandlines(int argc, char **argv, config_line_t **result)
static const struct {
const char *name;
int takes_argument;
} CMDLINE_ONLY_OPTIONS[] = {
{ "-f", 1 },
{ "--defaults-torrc", 1 },
{ "--hash-password", 1 },
{ "--dump-config", 1 },
{ "--list-fingerprint", 0 },
{ "--verify-config", 0 },
{ "--ignore-missing-torrc", 0 },
{ "--quiet", 0 },
{ "--hush", 0 },
{ "--version", 0 },
{ "-h", 0 },
{ "--help", 0 },
{ "--list-torrc-options", 0 },
{ "--digests", 0 },
{ "--nt-service", 0 },
{ "-nt-service", 0 },
{ NULL, 0 },
};
/** Helper: Read a list of configuration options from the command line. If
* successful, or if ignore_errors is set, put them in *<b>result</b>, put the
* commandline-only options in *<b>cmdline_result</b>, and return 0;
* otherwise, return -1 and leave *<b>result</b> and <b>cmdline_result</b>
* alone. */
int
config_parse_commandline(int argc, char **argv, int ignore_errors,
config_line_t **result,
config_line_t **cmdline_result)
{
config_line_t *param = NULL;
config_line_t *front = NULL;
config_line_t **new = &front;
char *s;
config_line_t *front_cmdline = NULL;
config_line_t **new_cmdline = &front_cmdline;
char *s, *arg;
int i = 1;
while (i < argc) {
unsigned command = CONFIG_LINE_NORMAL;
int want_arg = 1;
int is_cmdline = 0;
int j;
if (!strcmp(argv[i],"-f") ||
!strcmp(argv[i],"--defaults-torrc") ||
!strcmp(argv[i],"--hash-password")) {
i += 2; /* command-line option with argument. ignore them. */
continue;
} else if (!strcmp(argv[i],"--list-fingerprint") ||
!strcmp(argv[i],"--verify-config") ||
!strcmp(argv[i],"--ignore-missing-torrc") ||
!strcmp(argv[i],"--quiet") ||
!strcmp(argv[i],"--hush")) {
i += 1; /* command-line option. ignore it. */
continue;
} else if (!strcmp(argv[i],"--nt-service") ||
!strcmp(argv[i],"-nt-service")) {
i += 1;
continue;
for (j = 0; CMDLINE_ONLY_OPTIONS[j].name != NULL; ++j) {
if (!strcmp(argv[i], CMDLINE_ONLY_OPTIONS[j].name)) {
is_cmdline = 1;
want_arg = CMDLINE_ONLY_OPTIONS[j].takes_argument;
break;
}
}
*new = tor_malloc_zero(sizeof(config_line_t));
s = argv[i];
/* Each keyword may be prefixed with one or two dashes. */
@ -1843,22 +1871,38 @@ config_get_commandlines(int argc, char **argv, config_line_t **result)
}
if (want_arg && i == argc-1) {
log_warn(LD_CONFIG,"Command-line option '%s' with no value. Failing.",
argv[i]);
config_free_lines(front);
return -1;
if (ignore_errors) {
arg = strdup("");
} else {
log_warn(LD_CONFIG,"Command-line option '%s' with no value. Failing.",
argv[i]);
config_free_lines(front);
config_free_lines(front_cmdline);
return -1;
}
} else {
arg = want_arg ? tor_strdup(argv[i+1]) : strdup("");
}
(*new)->key = tor_strdup(config_expand_abbrev(&options_format, s, 1, 1));
(*new)->value = want_arg ? tor_strdup(argv[i+1]) : tor_strdup("");
(*new)->command = command;
(*new)->next = NULL;
param = tor_malloc_zero(sizeof(config_line_t));
param->key = is_cmdline ? tor_strdup(argv[i]) : tor_strdup(s);
param->value = arg;
param->command = command;
param->next = NULL;
log_debug(LD_CONFIG, "command line: parsed keyword '%s', value '%s'",
(*new)->key, (*new)->value);
param->key, param->value);
if (is_cmdline) {
*new_cmdline = param;
new_cmdline = &((*new_cmdline)->next);
} else {
*new = param;
new = &((*new)->next);
}
new = &((*new)->next);
i += want_arg ? 2 : 1;
}
*cmdline_result = front_cmdline;
*result = front;
return 0;
}
@ -2225,10 +2269,29 @@ options_init(or_options_t *options)
* include options that are the same as Tor's defaults.
*/
char *
options_dump(const or_options_t *options, int minimal)
options_dump(const or_options_t *options, int how_to_dump)
{
return config_dump(&options_format, global_default_options,
options, minimal, 0);
const or_options_t *use_defaults;
int minimal;
switch (how_to_dump) {
case OPTIONS_DUMP_MINIMAL:
use_defaults = global_default_options;
minimal = 1;
break;
case OPTIONS_DUMP_DEFAULTS:
use_defaults = NULL;
minimal = 1;
break;
case OPTIONS_DUMP_ALL:
use_defaults = NULL;
minimal = 0;
break;
default:
log_warn(LD_BUG, "Bogus value for how_to_dump==%d", how_to_dump);
return NULL;
}
return config_dump(&options_format, use_defaults, options, minimal, 0);
}
/** Return 0 if every element of sl is a string holding a decimal
@ -2345,6 +2408,14 @@ compute_publishserverdescriptor(or_options_t *options)
* */
#define RECOMMENDED_MIN_CIRCUIT_BUILD_TIMEOUT (10)
static int
options_validate_cb(void *old_options, void *options, void *default_options,
int from_setconf, char **msg)
{
return options_validate(old_options, options, default_options,
from_setconf, msg);
}
/** Return 0 if every setting in <b>options</b> is reasonable, is a
* permissible transition from <b>old_options</b>, and none of the
* testing-only settings differ from <b>default_options</b> unless in
@ -3703,26 +3774,26 @@ check_nickname_list(char **lst, const char *name, char **msg)
* filename if it doesn't exist.
*/
static char *
find_torrc_filename(int argc, char **argv,
find_torrc_filename(config_line_t *cmd_arg,
int defaults_file,
int *using_default_fname, int *ignore_missing_torrc)
{
char *fname=NULL;
int i;
config_line_t *p_index;
const char *fname_opt = defaults_file ? "--defaults-torrc" : "-f";
const char *ignore_opt = defaults_file ? NULL : "--ignore-missing-torrc";
if (defaults_file)
*ignore_missing_torrc = 1;
for (i = 1; i < argc; ++i) {
if (i < argc-1 && !strcmp(argv[i],fname_opt)) {
for (p_index = cmd_arg; p_index; p_index = p_index->next) {
if (!strcmp(p_index->key, fname_opt)) {
if (fname) {
log_warn(LD_CONFIG, "Duplicate %s options on command line.",
fname_opt);
tor_free(fname);
}
fname = expand_filename(argv[i+1]);
fname = expand_filename(p_index->value);
{
char *absfname;
@ -3732,8 +3803,7 @@ find_torrc_filename(int argc, char **argv,
}
*using_default_fname = 0;
++i;
} else if (ignore_opt && !strcmp(argv[i],ignore_opt)) {
} else if (ignore_opt && !strcmp(p_index->key,ignore_opt)) {
*ignore_missing_torrc = 1;
}
}
@ -3770,7 +3840,7 @@ find_torrc_filename(int argc, char **argv,
* Return the contents of the file on success, and NULL on failure.
*/
static char *
load_torrc_from_disk(int argc, char **argv, int defaults_file)
load_torrc_from_disk(config_line_t *cmd_arg, int defaults_file)
{
char *fname=NULL;
char *cf = NULL;
@ -3778,7 +3848,7 @@ load_torrc_from_disk(int argc, char **argv, int defaults_file)
int ignore_missing_torrc = 0;
char **fname_var = defaults_file ? &torrc_defaults_fname : &torrc_fname;
fname = find_torrc_filename(argc, argv, defaults_file,
fname = find_torrc_filename(cmd_arg, defaults_file,
&using_default_torrc, &ignore_missing_torrc);
tor_assert(fname);
log_debug(LD_CONFIG, "Opening config file \"%s\"", fname);
@ -3820,12 +3890,14 @@ int
options_init_from_torrc(int argc, char **argv)
{
char *cf=NULL, *cf_defaults=NULL;
int i, command;
int command;
int retval = -1;
static char **backup_argv;
static int backup_argc;
char *command_arg = NULL;
char *errmsg=NULL;
config_line_t *cmdline_only_options = NULL;
config_line_t *p_index = NULL;
if (argv) { /* first time we're called. save command line args */
backup_argv = argv;
@ -3834,45 +3906,50 @@ options_init_from_torrc(int argc, char **argv)
argv = backup_argv;
argc = backup_argc;
}
if (argc > 1 && (!strcmp(argv[1], "-h") || !strcmp(argv[1],"--help"))) {
/* Go through command-line variables */
if (!global_cmdline_options) {
/* Or we could redo the list every time we pass this place.
* It does not really matter */
if (config_parse_commandline(argc, argv, 0, &global_cmdline_options,
&cmdline_only_options) < 0) {
goto err;
}
}
if (config_line_find(cmdline_only_options, "-h") ||
config_line_find(cmdline_only_options, "--help")) {
print_usage();
exit(0);
}
if (argc > 1 && !strcmp(argv[1], "--list-torrc-options")) {
if (config_line_find(cmdline_only_options, "--list-torrc-options")) {
/* For documenting validating whether we've documented everything. */
list_torrc_options();
exit(0);
}
if (argc > 1 && (!strcmp(argv[1],"--version"))) {
if (config_line_find(cmdline_only_options, "--version")) {
printf("Tor version %s.\n",get_version());
exit(0);
}
if (argc > 1 && (!strcmp(argv[1],"--digests"))) {
if (config_line_find(cmdline_only_options, "--digests")) {
printf("Tor version %s.\n",get_version());
printf("%s", libor_get_digests());
printf("%s", tor_get_digests());
exit(0);
}
/* Go through command-line variables */
if (!global_cmdline_options) {
/* Or we could redo the list every time we pass this place.
* It does not really matter */
if (config_get_commandlines(argc, argv, &global_cmdline_options) < 0) {
goto err;
}
}
command = CMD_RUN_TOR;
for (i = 1; i < argc; ++i) {
if (!strcmp(argv[i],"--list-fingerprint")) {
for (p_index = cmdline_only_options; p_index; p_index = p_index->next) {
if (!strcmp(p_index->key,"--list-fingerprint")) {
command = CMD_LIST_FINGERPRINT;
} else if (!strcmp(argv[i],"--hash-password")) {
} else if (!strcmp(p_index->key, "--hash-password")) {
command = CMD_HASH_PASSWORD;
command_arg = tor_strdup( (i < argc-1) ? argv[i+1] : "");
++i;
} else if (!strcmp(argv[i],"--verify-config")) {
command_arg = p_index->value;
} else if (!strcmp(p_index->key, "--dump-config")) {
command = CMD_DUMP_CONFIG;
command_arg = p_index->value;
} else if (!strcmp(p_index->key, "--verify-config")) {
command = CMD_VERIFY_CONFIG;
}
}
@ -3881,8 +3958,8 @@ options_init_from_torrc(int argc, char **argv)
cf_defaults = tor_strdup("");
cf = tor_strdup("");
} else {
cf_defaults = load_torrc_from_disk(argc, argv, 1);
cf = load_torrc_from_disk(argc, argv, 0);
cf_defaults = load_torrc_from_disk(cmdline_only_options, 1);
cf = load_torrc_from_disk(cmdline_only_options, 0);
if (!cf)
goto err;
}
@ -3894,6 +3971,7 @@ options_init_from_torrc(int argc, char **argv)
tor_free(cf);
tor_free(cf_defaults);
config_free_lines(cmdline_only_options);
if (errmsg) {
log_warn(LD_CONFIG,"%s", errmsg);
tor_free(errmsg);
@ -3928,7 +4006,7 @@ options_init_from_string(const char *cf_defaults, const char *cf,
newoptions->magic_ = OR_OPTIONS_MAGIC;
options_init(newoptions);
newoptions->command = command;
newoptions->command_arg = command_arg;
newoptions->command_arg = command_arg ? tor_strdup(command_arg) : NULL;
for (i = 0; i < 2; ++i) {
const char *body = i==0 ? cf_defaults : cf;
@ -3992,7 +4070,7 @@ options_init_from_string(const char *cf_defaults, const char *cf,
newoptions->magic_ = OR_OPTIONS_MAGIC;
options_init(newoptions);
newoptions->command = command;
newoptions->command_arg = command_arg;
newoptions->command_arg = command_arg ? tor_strdup(command_arg) : NULL;
/* Assign all options a second time. */
for (i = 0; i < 2; ++i) {
@ -6096,7 +6174,7 @@ write_configuration_file(const char *fname, const or_options_t *options)
return -1;
}
if (!(new_conf = options_dump(options, 1))) {
if (!(new_conf = options_dump(options, OPTIONS_DUMP_MINIMAL))) {
log_warn(LD_BUG, "Couldn't get configuration string");
goto err;
}

View File

@ -32,7 +32,11 @@ int resolve_my_address(int warn_severity, const or_options_t *options,
const char **method_out, char **hostname_out);
int is_local_addr(const tor_addr_t *addr);
void options_init(or_options_t *options);
char *options_dump(const or_options_t *options, int minimal);
#define OPTIONS_DUMP_MINIMAL 1
#define OPTIONS_DUMP_DEFAULTS 2
#define OPTIONS_DUMP_ALL 3
char *options_dump(const or_options_t *options, int how_to_dump);
int options_init_from_torrc(int argc, char **argv);
setopt_err_t options_init_from_string(const char *cf_defaults, const char *cf,
int command, const char *command_arg, char **msg);
@ -96,6 +100,10 @@ int init_cookie_authentication(const char *fname, const char *header,
or_options_t *options_new(void);
int config_parse_commandline(int argc, char **argv, int ignore_errors,
config_line_t **result,
config_line_t **cmdline_result);
void config_register_addressmaps(const or_options_t *options);
/* XXXX024 move to connection_edge.h */
int addressmap_register_auto(const char *from, const char *to,

View File

@ -79,6 +79,21 @@ config_line_append(config_line_t **lst,
(*lst) = newline;
}
/** Return the line in <b>lines</b> whose key is exactly <b>key</b>, or NULL
* if no such key exists. For handling commandline-only options only; other
* options should be looked up in the appropriate data structure. */
const config_line_t *
config_line_find(const config_line_t *lines,
const char *key)
{
const config_line_t *cl;
for (cl = lines; cl; cl = cl->next) {
if (!strcmp(cl->key, key))
return cl;
}
return NULL;
}
/** Helper: parse the config string and strdup into key/value
* strings. Set *result to the list, or NULL if parsing the string
* failed. Return 0 on success, -1 on failure. Warn and ignore any
@ -1059,8 +1074,8 @@ config_dump(const config_format_t *fmt, const void *default_options,
/* XXX use a 1 here so we don't add a new log line while dumping */
if (default_options == NULL) {
if (fmt->validate_fn(NULL, defaults_tmp, 1, &msg) < 0) {
log_err(LD_BUG, "Failed to validate default config.");
if (fmt->validate_fn(NULL, defaults_tmp, defaults_tmp, 1, &msg) < 0) {
log_err(LD_BUG, "Failed to validate default config: %s", msg);
tor_free(msg);
tor_assert(0);
}

View File

@ -71,7 +71,7 @@ typedef struct config_var_description_t {
/** Type of a callback to validate whether a given configuration is
* well-formed and consistent. See options_trial_assign() for documentation
* of arguments. */
typedef int (*validate_fn_t)(void*,void*,int,char**);
typedef int (*validate_fn_t)(void*,void*,void*,int,char**);
/** Information on the keys, value types, key-to-struct-member mappings,
* variable descriptions, validation functions, and abbreviations for a
@ -103,6 +103,8 @@ void *config_new(const config_format_t *fmt);
void config_line_append(config_line_t **lst,
const char *key, const char *val);
config_line_t *config_lines_dup(const config_line_t *inp);
const config_line_t *config_line_find(const config_line_t *lines,
const char *key);
void config_free(const config_format_t *fmt, void *options);
int config_lines_eq(config_line_t *a, config_line_t *b);
int config_count_key(const config_line_t *a, const char *key);

View File

@ -1406,7 +1406,7 @@ getinfo_helper_misc(control_connection_t *conn, const char *question,
} else if (!strcmp(question, "config-defaults-file")) {
*answer = tor_strdup(get_torrc_fname(1));
} else if (!strcmp(question, "config-text")) {
*answer = options_dump(get_options(), 1);
*answer = options_dump(get_options(), OPTIONS_DUMP_MINIMAL);
} else if (!strcmp(question, "info/names")) {
*answer = list_getinfo_options();
} else if (!strcmp(question, "dormant")) {

View File

@ -21,6 +21,7 @@
#include "circuituse.h"
#include "command.h"
#include "config.h"
#include "confparse.h"
#include "connection.h"
#include "connection_edge.h"
#include "connection_or.h"
@ -2325,7 +2326,7 @@ int
tor_init(int argc, char *argv[])
{
char buf[256];
int i, quiet = 0;
int quiet = 0;
time_of_process_start = time(NULL);
init_connection_lists();
/* Have the log set up with our application name. */
@ -2338,17 +2339,28 @@ tor_init(int argc, char *argv[])
addressmap_init(); /* Init the client dns cache. Do it always, since it's
* cheap. */
{
/* We search for the "quiet" option first, since it decides whether we
* will log anything at all to the command line. */
for (i=1;i<argc;++i) {
if (!strcmp(argv[i], "--hush"))
quiet = 1;
if (!strcmp(argv[i], "--quiet"))
quiet = 2;
/* --version implies --quiet */
if (!strcmp(argv[i], "--version"))
quiet = 2;
config_line_t *opts = NULL, *cmdline_opts = NULL;
const config_line_t *cl;
(void) config_parse_commandline(argc, argv, 1, &opts, &cmdline_opts);
for (cl = cmdline_opts; cl; cl = cl->next) {
if (!strcmp(cl->key, "--hush"))
quiet = 1;
if (!strcmp(cl->key, "--quiet") ||
!strcmp(cl->key, "--dump-config"))
quiet = 2;
/* --version, --digests, and --help imply --husth */
if (!strcmp(cl->key, "--version") || !strcmp(cl->key, "--digests") ||
!strcmp(cl->key, "--list-torrc-options") ||
!strcmp(cl->key, "-h") || !strcmp(cl->key, "--help"))
quiet = 1;
}
config_free_lines(opts);
config_free_lines(cmdline_opts);
}
/* give it somewhere to log to initially */
switch (quiet) {
case 2:
@ -2592,7 +2604,7 @@ do_list_fingerprint(void)
const char *nickname = get_options()->Nickname;
if (!server_mode(get_options())) {
log_err(LD_GENERAL,
"Clients don't have long-term identity keys. Exiting.\n");
"Clients don't have long-term identity keys. Exiting.");
return -1;
}
tor_assert(nickname);
@ -2630,6 +2642,34 @@ do_hash_password(void)
printf("16:%s\n",output);
}
/** Entry point for configuration dumping: write the configuration to
* stdout. */
static int
do_dump_config(void)
{
const or_options_t *options = get_options();
const char *arg = options->command_arg;
int how;
char *opts;
if (!strcmp(arg, "short")) {
how = OPTIONS_DUMP_MINIMAL;
} else if (!strcmp(arg, "non-builtin")) {
how = OPTIONS_DUMP_DEFAULTS;
} else if (!strcmp(arg, "full")) {
how = OPTIONS_DUMP_ALL;
} else {
printf("%s is not a recognized argument to --dump-config. "
"Please select 'short', 'non-builtin', or 'full'", arg);
return -1;
}
opts = options_dump(options, how);
printf("%s", opts);
tor_free(opts);
return 0;
}
#if defined (WINCE)
int
find_flashcard_path(PWCHAR path, size_t size)
@ -2844,6 +2884,9 @@ tor_main(int argc, char *argv[])
printf("Configuration was valid\n");
result = 0;
break;
case CMD_DUMP_CONFIG:
result = do_dump_config();
break;
case CMD_RUN_UNITTESTS: /* only set by test.c */
default:
log_warn(LD_BUG,"Illegal command number %d: internal error.",

View File

@ -3398,9 +3398,9 @@ typedef struct {
/** What should the tor process actually do? */
enum {
CMD_RUN_TOR=0, CMD_LIST_FINGERPRINT, CMD_HASH_PASSWORD,
CMD_VERIFY_CONFIG, CMD_RUN_UNITTESTS
CMD_VERIFY_CONFIG, CMD_RUN_UNITTESTS, CMD_DUMP_CONFIG
} command;
const char *command_arg; /**< Argument for command-line option. */
char *command_arg; /**< Argument for command-line option. */
config_line_t *Logs; /**< New-style list of configuration lines
* for logs */

242
src/test/test_cmdline_args.py Executable file
View File

@ -0,0 +1,242 @@
#!/usr/bin/python
import binascii
import hashlib
import os
import re
import shutil
import subprocess
import tempfile
import unittest
TOR = "./src/or/tor-cov"
TOPDIR = "."
class UnexpectedSuccess(Exception):
pass
class UnexpectedFailure(Exception):
pass
def contents(fn):
f = open(fn)
try:
return f.read()
finally:
f.close()
def run_tor(args, failure=False):
p = subprocess.Popen([TOR] + args, stdout=subprocess.PIPE)
output, _ = p.communicate()
result = p.poll()
if result and not failure:
raise UnexpectedFailure()
elif not result and failure:
raise UnexpectedSuccess()
return output
def spaceify_fp(fp):
for i in xrange(0, len(fp), 4):
yield fp[i:i+4]
def lines(s):
out = s.split("\n")
if out and out[-1] == '':
del out[-1]
return out
def strip_log_junk(line):
m = re.match(r'([^\[]+\[[a-z]*\] *)(.*)', line)
if not m:
return ""+line
return m.group(2).strip()
class CmdlineTests(unittest.TestCase):
def test_version(self):
out = run_tor(["--version"])
self.failUnless(out.startswith("Tor version "))
self.assertEquals(len(lines(out)), 1)
def test_quiet(self):
out = run_tor(["--quiet", "--quumblebluffin", "1"], failure=True)
self.assertEquals(out, "")
def test_help(self):
out = run_tor(["--help"], failure=False)
out2 = run_tor(["-h"], failure=False)
self.assert_(out.startswith("Copyright (c) 2001"))
self.assert_(out.endswith(
"tor -f <torrc> [args]\n"
"See man page for options, or https://www.torproject.org/ for documentation.\n"))
self.assert_(out == out2)
def test_hush(self):
torrc = tempfile.NamedTemporaryFile(delete=False)
torrc.close()
try:
out = run_tor(["--hush", "-f", torrc.name,
"--quumblebluffin", "1"], failure=True)
finally:
os.unlink(torrc.name)
self.assertEquals(len(lines(out)), 2)
ln = [ strip_log_junk(l) for l in lines(out) ]
self.assertEquals(ln[0], "Failed to parse/validate config: Unknown option 'quumblebluffin'. Failing.")
self.assertEquals(ln[1], "Reading config failed--see warnings above.")
def test_missing_argument(self):
out = run_tor(["--hush", "--hash-password"], failure=True)
self.assertEquals(len(lines(out)), 2)
ln = [ strip_log_junk(l) for l in lines(out) ]
self.assertEquals(ln[0], "Command-line option '--hash-password' with no value. Failing.")
def test_hash_password(self):
out = run_tor(["--hash-password", "woodwose"])
result = lines(out)[-1]
self.assertEquals(result[:3], "16:")
self.assertEquals(len(result), 61)
r = binascii.a2b_hex(result[3:])
self.assertEquals(len(r), 29)
salt, how, hashed = r[:8], r[8], r[9:]
self.assertEquals(len(hashed), 20)
count = (16 + (ord(how) & 15)) << ((ord(how) >> 4) + 6)
stuff = salt + "woodwose"
repetitions = count // len(stuff) + 1
inp = stuff * repetitions
inp = inp[:count]
self.assertEquals(hashlib.sha1(inp).digest(), hashed)
def test_digests(self):
main_c = os.path.join(TOPDIR, "src", "or", "main.c")
if os.stat(TOR).st_mtime < os.stat(main_c).st_mtime:
self.skipTest(TOR+" not up to date")
out = run_tor(["--digests"])
main_line = [ l for l in lines(out) if l.endswith("/main.c") ]
digest, name = main_line[0].split()
actual = hashlib.sha1(open(main_c).read()).hexdigest()
self.assertEquals(digest, actual)
def test_dump_options(self):
default_torrc = tempfile.NamedTemporaryFile(delete=False)
torrc = tempfile.NamedTemporaryFile(delete=False)
torrc.write("SocksPort 9999")
torrc.close()
default_torrc.write("SafeLogging 0")
default_torrc.close()
out_sh = out_nb = out_fl = None
opts = [ "-f", torrc.name,
"--defaults-torrc", default_torrc.name ]
try:
out_sh = run_tor(["--dump-config", "short"]+opts)
out_nb = run_tor(["--dump-config", "non-builtin"]+opts)
out_fl = run_tor(["--dump-config", "full"]+opts)
out_nr = run_tor(["--dump-config", "bliznert"]+opts,
failure=True)
out_verif = run_tor(["--verify-config"]+opts)
finally:
os.unlink(torrc.name)
os.unlink(default_torrc.name)
self.assertEquals(len(lines(out_sh)), 2)
self.assert_(lines(out_sh)[0].startswith("DataDirectory "))
self.assertEquals(lines(out_sh)[1:],
[ "SocksPort 9999" ])
self.assertEquals(len(lines(out_nb)), 2)
self.assertEquals(lines(out_nb),
[ "SafeLogging 0",
"SocksPort 9999" ])
out_fl = lines(out_fl)
self.assert_(len(out_fl) > 100)
self.assertIn("SocksPort 9999", out_fl)
self.assertIn("SafeLogging 0", out_fl)
self.assertIn("ClientOnly 0", out_fl)
self.assert_(out_verif.endswith("Configuration was valid\n"))
def test_list_fingerprint(self):
tmpdir = tempfile.mkdtemp(prefix='ttca_')
torrc = tempfile.NamedTemporaryFile(delete=False)
torrc.write("ORPort 9999\n")
torrc.write("DataDirectory %s\n"%tmpdir)
torrc.write("Nickname tippi")
torrc.close()
opts = ["-f", torrc.name]
try:
out = run_tor(["--list-fingerprint"]+opts)
fp = contents(os.path.join(tmpdir, "fingerprint"))
finally:
os.unlink(torrc.name)
shutil.rmtree(tmpdir)
out = lines(out)
lastlog = strip_log_junk(out[-2])
lastline = out[-1]
fp = fp.strip()
nn_fp = fp.split()[0]
space_fp = " ".join(spaceify_fp(fp.split()[1]))
self.assertEquals(lastlog,
"Your Tor server's identity key fingerprint is '%s'"%fp)
self.assertEquals(lastline, "tippi %s"%space_fp)
self.assertEquals(nn_fp, "tippi")
def test_list_options(self):
out = lines(run_tor(["--list-torrc-options"]))
self.assert_(len(out)>100)
self.assert_(out[0] <= 'AccountingMax')
self.assert_("UseBridges" in out)
self.assert_("SocksPort" in out)
def test_cmdline_args(self):
default_torrc = tempfile.NamedTemporaryFile(delete=False)
torrc = tempfile.NamedTemporaryFile(delete=False)
torrc.write("SocksPort 9999\n")
torrc.write("SocksPort 9998\n")
torrc.write("ORPort 9000\n")
torrc.write("ORPort 9001\n")
torrc.write("Nickname eleventeen\n")
torrc.write("ControlPort 9500\n")
torrc.close()
default_torrc.write("")
default_torrc.close()
out_sh = out_nb = out_fl = None
opts = [ "-f", torrc.name,
"--defaults-torrc", default_torrc.name,
"--dump-config", "short" ]
try:
out_1 = run_tor(opts)
out_2 = run_tor(opts+["+ORPort", "9003",
"SocksPort", "9090",
"/ControlPort",
"/TransPort",
"+ExtORPort", "9005"])
finally:
os.unlink(torrc.name)
os.unlink(default_torrc.name)
out_1 = [ l for l in lines(out_1) if not l.startswith("DataDir") ]
out_2 = [ l for l in lines(out_2) if not l.startswith("DataDir") ]
self.assertEquals(out_1,
["ControlPort 9500",
"Nickname eleventeen",
"ORPort 9000",
"ORPort 9001",
"SocksPort 9999",
"SocksPort 9998"])
self.assertEquals(out_2,
["ExtORPort 9005",
"Nickname eleventeen",
"ORPort 9000",
"ORPort 9001",
"ORPort 9003",
"SocksPort 9090"])
if __name__ == '__main__':
unittest.main()