mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-10 13:13:44 +01:00
Merge branch 'bug4647_squashed'
This commit is contained in:
commit
e35c972851
18
changes/bug4647
Normal file
18
changes/bug4647
Normal 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.
|
||||
|
||||
|
@ -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**::
|
||||
|
220
src/or/config.c
220
src/or/config.c
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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")) {
|
||||
|
@ -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.",
|
||||
|
@ -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
242
src/test/test_cmdline_args.py
Executable 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()
|
Loading…
Reference in New Issue
Block a user