aboutsummaryrefslogtreecommitdiff
path: root/src/or
diff options
context:
space:
mode:
Diffstat (limited to 'src/or')
-rw-r--r--src/or/Makefile.am9
-rw-r--r--src/or/config.c338
-rw-r--r--src/or/config.h8
-rw-r--r--src/or/connection.c68
-rw-r--r--src/or/connection.h3
-rw-r--r--src/or/connection_or.c42
-rw-r--r--src/or/control.c8
-rw-r--r--src/or/dirserv.c2
-rw-r--r--src/or/dirvote.c32
-rw-r--r--src/or/dirvote.h3
-rw-r--r--src/or/dns.c7
-rw-r--r--src/or/hibernate.c11
-rw-r--r--src/or/main.c57
-rw-r--r--src/or/or.h27
-rw-r--r--src/or/router.c12
-rw-r--r--src/or/router.h2
-rw-r--r--src/or/routerlist.c6
-rw-r--r--src/or/transports.c326
-rw-r--r--src/or/transports.h7
19 files changed, 750 insertions, 218 deletions
diff --git a/src/or/Makefile.am b/src/or/Makefile.am
index 67adf504df..a5682081ae 100644
--- a/src/or/Makefile.am
+++ b/src/or/Makefile.am
@@ -126,8 +126,9 @@ tor_main.o: micro-revision.i
micro-revision.i: FORCE
@rm -f micro-revision.tmp; \
- if test -d ../../.git && test -x "`which git 2>&1;true`"; then \
- HASH="`git rev-parse --short=16 HEAD`"; \
+ if test -d "$(top_srcdir)/.git" && \
+ test -x "`which git 2>&1;true`"; then \
+ HASH="`cd "$(top_srcdir)" && git rev-parse --short=16 HEAD`"; \
echo \"$$HASH\" > micro-revision.tmp; \
fi; \
if test ! -f micro-revision.tmp ; then \
@@ -141,10 +142,10 @@ micro-revision.i: FORCE
or_sha1.i: $(tor_SOURCES) $(libtor_a_SOURCES)
if test "@SHA1SUM@" != none; then \
- @SHA1SUM@ $(tor_SOURCES) $(libtor_a_SOURCES) | \
+ (cd "$(srcdir)" && @SHA1SUM@ $(tor_SOURCES) $(libtor_a_SOURCES)) | \
@SED@ -n 's/^\(.*\)$$/"\1\\n"/p' > or_sha1.i; \
elif test "@OPENSSL@" != none; then \
- @OPENSSL@ sha1 $(tor_SOURCES) $(libtor_a_SOURCES) | \
+ (cd "$(srcdir)" && @OPENSSL@ sha1 $(tor_SOURCES) $(libtor_a_SOURCES)) | \
@SED@ -n 's/SHA1(\(.*\))= \(.*\)/"\2 \1\\n"/p' > or_sha1.i; \
else \
rm or_sha1.i; \
diff --git a/src/or/config.c b/src/or/config.c
index 06914b62af..ab991a4f6e 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -231,6 +231,7 @@ static config_var_t _option_vars[] = {
V(CountPrivateBandwidth, BOOL, "0"),
V(DataDirectory, FILENAME, NULL),
OBSOLETE("DebugLogFile"),
+ V(DisableNetwork, BOOL, "0"),
V(DirAllowPrivateAddresses, BOOL, NULL),
V(TestingAuthDirTimeToLearnReachability, INTERVAL, "30 minutes"),
V(DirListenAddress, LINELIST, NULL),
@@ -246,6 +247,7 @@ static config_var_t _option_vars[] = {
V(DirReqStatistics, BOOL, "1"),
VAR("DirServer", LINELIST, DirServers, NULL),
V(DisableAllSwap, BOOL, "0"),
+ V(DisableDebuggerAttachment, BOOL, "1"),
V(DisableIOCP, BOOL, "1"),
V(DynamicDHGroups, BOOL, "1"),
V(DNSPort, LINELIST, NULL),
@@ -406,6 +408,7 @@ static config_var_t _option_vars[] = {
V(UseEntryGuards, BOOL, "1"),
V(UseMicrodescriptors, AUTOBOOL, "auto"),
V(User, STRING, NULL),
+ V(UserspaceIOCPBuffers, BOOL, "0"),
VAR("V1AuthoritativeDirectory",BOOL, V1AuthoritativeDir, "0"),
VAR("V2AuthoritativeDirectory",BOOL, V2AuthoritativeDir, "0"),
VAR("V3AuthoritativeDirectory",BOOL, V3AuthoritativeDir, "0"),
@@ -660,8 +663,12 @@ static const config_format_t state_format = {
/** Command-line and config-file options. */
static or_options_t *global_options = NULL;
+/** DOCDOC */
+static or_options_t *global_default_options = NULL;
/** Name of most recently read torrc file. */
static char *torrc_fname = NULL;
+/** DOCDOC */
+static char *torrc_defaults_fname;
/** Persistent serialized state. */
static or_state_t *global_state = NULL;
/** Configuration Options set by command line. */
@@ -805,6 +812,8 @@ config_free_all(void)
{
or_options_free(global_options);
global_options = NULL;
+ or_options_free(global_default_options);
+ global_default_options = NULL;
config_free(&state_format, global_state);
global_state = NULL;
@@ -820,6 +829,7 @@ config_free_all(void)
}
tor_free(torrc_fname);
+ tor_free(torrc_defaults_fname);
tor_free(_version);
tor_free(global_dirfrontpagecontents);
}
@@ -1092,13 +1102,22 @@ options_act_reversible(const or_options_t *old_options, char **msg)
consider_hibernation(time(NULL));
/* Launch the listeners. (We do this before we setuid, so we can bind to
- * ports under 1024.) We don't want to rebind if we're hibernating. */
+ * ports under 1024.) We don't want to rebind if we're hibernating. If
+ * networking is disabled, this will close all but the control listeners,
+ * but disable those. */
if (!we_are_hibernating()) {
if (retry_all_listeners(replaced_listeners, new_listeners) < 0) {
*msg = tor_strdup("Failed to bind one of the listener ports.");
goto rollback;
}
}
+ if (options->DisableNetwork) {
+ /* Aggressively close non-controller stuff, NOW */
+ log_notice(LD_NET, "DisableNetwork is set. Tor will not make or accept "
+ "non-control network connections. Shutting down all existing "
+ "connections.");
+ connection_mark_all_noncontrol_connections();
+ }
}
#if defined(HAVE_NET_IF_H) && defined(HAVE_NET_PFVAR_H)
@@ -1304,6 +1323,14 @@ options_act(const or_options_t *old_options)
const int transition_affects_workers =
old_options && options_transition_affects_workers(old_options, options);
+ /* disable ptrace and later, other basic debugging techniques */
+ if (options->DisableDebuggerAttachment) {
+ tor_disable_debugger_attach();
+ } else {
+ log_notice(LD_CONFIG,"Debugger attachment enabled "
+ "for unprivileged users.");
+ }
+
if (running_tor && !have_lockfile()) {
if (try_locking(options, 1) < 0)
return -1;
@@ -1767,7 +1794,11 @@ config_get_commandlines(int argc, char **argv, config_line_t **result)
int i = 1;
while (i < argc) {
+ unsigned command = CONFIG_LINE_NORMAL;
+ int want_arg = 1;
+
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;
@@ -1784,13 +1815,6 @@ config_get_commandlines(int argc, char **argv, config_line_t **result)
continue;
}
- if (i == argc-1) {
- log_warn(LD_CONFIG,"Command-line option '%s' with no value. Failing.",
- argv[i]);
- config_free_lines(front);
- return -1;
- }
-
*new = tor_malloc_zero(sizeof(config_line_t));
s = argv[i];
@@ -1799,15 +1823,33 @@ config_get_commandlines(int argc, char **argv, config_line_t **result)
s++;
if (*s == '-')
s++;
+ /* Figure out the command, if any. */
+ if (*s == '+') {
+ s++;
+ command = CONFIG_LINE_APPEND;
+ } else if (*s == '/') {
+ s++;
+ command = CONFIG_LINE_CLEAR;
+ /* A 'clear' command has no argument. */
+ want_arg = 0;
+ }
+
+ 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;
+ }
(*new)->key = tor_strdup(expand_abbrev(&options_format, s, 1, 1));
- (*new)->value = tor_strdup(argv[i+1]);
+ (*new)->value = want_arg ? tor_strdup(argv[i+1]) : tor_strdup("");
+ (*new)->command = command;
(*new)->next = NULL;
log(LOG_DEBUG, LD_CONFIG, "command line: parsed keyword '%s', value '%s'",
(*new)->key, (*new)->value);
new = &((*new)->next);
- i += 2;
+ i += want_arg ? 2 : 1;
}
*result = front;
return 0;
@@ -1822,7 +1864,7 @@ config_line_append(config_line_t **lst,
{
config_line_t *newline;
- newline = tor_malloc(sizeof(config_line_t));
+ newline = tor_malloc_zero(sizeof(config_line_t));
newline->key = tor_strdup(key);
newline->value = tor_strdup(val);
newline->next = NULL;
@@ -1835,9 +1877,12 @@ config_line_append(config_line_t **lst,
/** 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
- * misformatted lines. */
+ * misformatted lines.
+ *
+ * If <b>extended</b> is set, then treat keys beginning with / and with + as
+ * indicating "clear" and "append" respectively. */
int
-config_get_lines(const char *string, config_line_t **result)
+config_get_lines(const char *string, config_line_t **result, int extended)
{
config_line_t *list = NULL, **next;
char *k, *v;
@@ -1853,13 +1898,30 @@ config_get_lines(const char *string, config_line_t **result)
return -1;
}
if (k && v) {
+ unsigned command = CONFIG_LINE_NORMAL;
+ if (extended) {
+ if (k[0] == '+') {
+ char *k_new = tor_strdup(k+1);
+ tor_free(k);
+ k = k_new;
+ command = CONFIG_LINE_APPEND;
+ } else if (k[0] == '/') {
+ char *k_new = tor_strdup(k+1);
+ tor_free(k);
+ k = k_new;
+ tor_free(v);
+ v = tor_strdup("");
+ command = CONFIG_LINE_CLEAR;
+ }
+ }
/* This list can get long, so we keep a pointer to the end of it
* rather than using config_line_append over and over and getting
* n^2 performance. */
- *next = tor_malloc(sizeof(config_line_t));
+ *next = tor_malloc_zero(sizeof(config_line_t));
(*next)->key = k;
(*next)->value = v;
(*next)->next = NULL;
+ (*next)->command = command;
next = &((*next)->next);
} else {
tor_free(k);
@@ -2087,7 +2149,19 @@ config_assign_value(const config_format_t *fmt, or_options_t *options,
case CONFIG_TYPE_LINELIST:
case CONFIG_TYPE_LINELIST_S:
- config_line_append((config_line_t**)lvalue, c->key, c->value);
+ {
+ config_line_t *lastval = *(config_line_t**)lvalue;
+ if (lastval && lastval->fragile) {
+ if (c->command != CONFIG_LINE_APPEND) {
+ config_free_lines(lastval);
+ *(config_line_t**)lvalue = NULL;
+ } else {
+ lastval->fragile = 0;
+ }
+ }
+
+ config_line_append((config_line_t**)lvalue, c->key, c->value);
+ }
break;
case CONFIG_TYPE_OBSOLETE:
log_warn(LD_CONFIG, "Skipping obsolete configuration option '%s'", c->key);
@@ -2103,6 +2177,28 @@ config_assign_value(const config_format_t *fmt, or_options_t *options,
return 0;
}
+/** Mark every linelist in <b>options<b> "fragile", so that fresh assignments
+ * to it will replace old ones. */
+static void
+config_mark_lists_fragile(const config_format_t *fmt, or_options_t *options)
+{
+ int i;
+ tor_assert(fmt);
+ tor_assert(options);
+
+ for (i = 0; fmt->vars[i].name; ++i) {
+ const config_var_t *var = &fmt->vars[i];
+ config_line_t *list;
+ if (var->type != CONFIG_TYPE_LINELIST &&
+ var->type != CONFIG_TYPE_LINELIST_V)
+ continue;
+
+ list = *(config_line_t **)STRUCT_VAR_P(options, var->var_offset);
+ if (list)
+ list->fragile = 1;
+ }
+}
+
/** If <b>c</b> is a syntactically valid configuration line, update
* <b>options</b> with its value and return 0. Otherwise return -1 for bad
* key, -2 for bad value.
@@ -2145,8 +2241,9 @@ config_assign_line(const config_format_t *fmt, or_options_t *options,
if (!strlen(c->value)) {
/* reset or clear it, then return */
if (!clear_first) {
- if (var->type == CONFIG_TYPE_LINELIST ||
- var->type == CONFIG_TYPE_LINELIST_S) {
+ if ((var->type == CONFIG_TYPE_LINELIST ||
+ var->type == CONFIG_TYPE_LINELIST_S) &&
+ c->command != CONFIG_LINE_CLEAR) {
/* We got an empty linelist from the torrc or command line.
As a special case, call this an error. Warn and ignore. */
log_warn(LD_CONFIG,
@@ -2156,6 +2253,8 @@ config_assign_line(const config_format_t *fmt, or_options_t *options,
}
}
return 0;
+ } else if (c->command == CONFIG_LINE_CLEAR && !clear_first) {
+ option_reset(fmt, options, var, use_defaults);
}
if (options_seen && (var->type != CONFIG_TYPE_LINELIST &&
@@ -2250,7 +2349,7 @@ config_lines_dup(const config_line_t *inp)
config_line_t *result = NULL;
config_line_t **next_out = &result;
while (inp) {
- *next_out = tor_malloc(sizeof(config_line_t));
+ *next_out = tor_malloc_zero(sizeof(config_line_t));
(*next_out)->key = tor_strdup(inp->key);
(*next_out)->value = tor_strdup(inp->value);
inp = inp->next;
@@ -2487,6 +2586,12 @@ config_assign(const config_format_t *fmt, void *options, config_line_t *list,
list = list->next;
}
bitarray_free(options_seen);
+
+ /** Now we're done assigning a group of options to the configuration.
+ * Subsequent group assignments should _replace_ linelists, not extend
+ * them. */
+ config_mark_lists_fragile(fmt, options);
+
return 0;
}
@@ -2982,24 +3087,30 @@ config_init(const config_format_t *fmt, void *options)
* Else, if comment_defaults, write default values as comments.
*/
static char *
-config_dump(const config_format_t *fmt, const void *options, int minimal,
+config_dump(const config_format_t *fmt, const void *default_options,
+ const void *options, int minimal,
int comment_defaults)
{
smartlist_t *elements;
- or_options_t *defaults;
+ const or_options_t *defaults = default_options;
+ void *defaults_tmp = NULL;
config_line_t *line, *assigned;
char *result;
int i;
char *msg = NULL;
- defaults = config_alloc(fmt);
- config_init(fmt, defaults);
+ if (defaults == NULL) {
+ defaults = defaults_tmp = config_alloc(fmt);
+ config_init(fmt, defaults_tmp);
+ }
/* XXX use a 1 here so we don't add a new log line while dumping */
- if (fmt->validate_fn(NULL,defaults, 1, &msg) < 0) {
- log_err(LD_BUG, "Failed to validate default config.");
- tor_free(msg);
- tor_assert(0);
+ if (default_options == NULL) {
+ if (fmt->validate_fn(NULL, defaults_tmp, 1, &msg) < 0) {
+ log_err(LD_BUG, "Failed to validate default config.");
+ tor_free(msg);
+ tor_assert(0);
+ }
}
elements = smartlist_create();
@@ -3041,7 +3152,8 @@ config_dump(const config_format_t *fmt, const void *options, int minimal,
result = smartlist_join_strings(elements, "", 0, NULL);
SMARTLIST_FOREACH(elements, char *, cp, tor_free(cp));
smartlist_free(elements);
- config_free(fmt, defaults);
+ if (defaults_tmp)
+ config_free(fmt, defaults_tmp);
return result;
}
@@ -3052,7 +3164,8 @@ config_dump(const config_format_t *fmt, const void *options, int minimal,
char *
options_dump(const or_options_t *options, int minimal)
{
- return config_dump(&options_format, options, minimal, 0);
+ return config_dump(&options_format, global_default_options,
+ options, minimal, 0);
}
/** Return 0 if every element of sl is a string holding a decimal
@@ -4133,6 +4246,7 @@ options_transition_affects_descriptor(const or_options_t *old_options,
old_options->ORPort != new_options->ORPort ||
old_options->DirPort != new_options->DirPort ||
old_options->ClientOnly != new_options->ClientOnly ||
+ old_options->DisableNetwork != new_options->DisableNetwork ||
old_options->_PublishServerDescriptor !=
new_options->_PublishServerDescriptor ||
get_effective_bwrate(old_options) != get_effective_bwrate(new_options) ||
@@ -4206,17 +4320,25 @@ get_windows_conf_root(void)
}
#endif
-/** Return the default location for our torrc file. */
+/** Return the default location for our torrc file.
+ * DOCDOC defaults_file */
static const char *
-get_default_conf_file(void)
+get_default_conf_file(int defaults_file)
{
#ifdef MS_WINDOWS
- static char path[MAX_PATH+1];
- strlcpy(path, get_windows_conf_root(), MAX_PATH);
- strlcat(path,"\\torrc",MAX_PATH);
- return path;
+ if (defaults_file) {
+ static char defaults_path[MAX_PATH+1];
+ tor_snprintf(defaults_path, MAX_PATH, "%s\\torrc-defaults",
+ get_windows_conf_root());
+ return defaults_path;
+ } else {
+ static char path[MAX_PATH+1];
+ tor_snprintf(path, MAX_PATH, "%s\\torrc",
+ get_windows_conf_root());
+ return path;
+ }
#else
- return (CONFDIR "/torrc");
+ return defaults_file ? CONFDIR "/torrc-defaults" : CONFDIR "/torrc";
#endif
}
@@ -4249,37 +4371,46 @@ check_nickname_list(const char *lst, const char *name, char **msg)
return r;
}
-/** Learn config file name from command line arguments, or use the default */
+/** Learn config file name from command line arguments, or use the default,
+ * DOCDOC defaults_file */
static char *
find_torrc_filename(int argc, char **argv,
+ int defaults_file,
int *using_default_torrc, int *ignore_missing_torrc)
{
char *fname=NULL;
int i;
+ 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],"-f")) {
+ if (i < argc-1 && !strcmp(argv[i],fname_opt)) {
if (fname) {
- log(LOG_WARN, LD_CONFIG, "Duplicate -f options on command line.");
+ log(LOG_WARN, LD_CONFIG, "Duplicate %s options on command line.",
+ fname_opt);
tor_free(fname);
}
fname = expand_filename(argv[i+1]);
*using_default_torrc = 0;
++i;
- } else if (!strcmp(argv[i],"--ignore-missing-torrc")) {
+ } else if (ignore_opt && !strcmp(argv[i],ignore_opt)) {
*ignore_missing_torrc = 1;
}
}
if (*using_default_torrc) {
/* didn't find one, try CONFDIR */
- const char *dflt = get_default_conf_file();
+ const char *dflt = get_default_conf_file(defaults_file);
if (dflt && file_status(dflt) == FN_FILE) {
fname = tor_strdup(dflt);
} else {
#ifndef MS_WINDOWS
- char *fn;
- fn = expand_filename("~/.torrc");
+ char *fn = NULL;
+ if (!defaults_file)
+ fn = expand_filename("~/.torrc");
if (fn && file_status(fn) == FN_FILE) {
fname = fn;
} else {
@@ -4294,31 +4425,34 @@ find_torrc_filename(int argc, char **argv,
return fname;
}
-/** Load torrc from disk, setting torrc_fname if successful */
+/** Load torrc from disk, setting torrc_fname if successful.
+ * DOCDOC defaults_file */
static char *
-load_torrc_from_disk(int argc, char **argv)
+load_torrc_from_disk(int argc, char **argv, int defaults_file)
{
char *fname=NULL;
char *cf = NULL;
int using_default_torrc = 1;
int ignore_missing_torrc = 0;
+ char **fname_var = defaults_file ? &torrc_fname : &torrc_defaults_fname;
- fname = find_torrc_filename(argc, argv,
+ fname = find_torrc_filename(argc, argv, defaults_file,
&using_default_torrc, &ignore_missing_torrc);
tor_assert(fname);
log(LOG_DEBUG, LD_CONFIG, "Opening config file \"%s\"", fname);
- tor_free(torrc_fname);
- torrc_fname = fname;
+ tor_free(*fname_var);
+ *fname_var = fname;
/* Open config file */
if (file_status(fname) != FN_FILE ||
!(cf = read_file_to_str(fname,0,NULL))) {
- if (using_default_torrc == 1 || ignore_missing_torrc ) {
- log(LOG_NOTICE, LD_CONFIG, "Configuration file \"%s\" not present, "
- "using reasonable defaults.", fname);
+ if (using_default_torrc == 1 || ignore_missing_torrc) {
+ if (!defaults_file)
+ log(LOG_NOTICE, LD_CONFIG, "Configuration file \"%s\" not present, "
+ "using reasonable defaults.", fname);
tor_free(fname); /* sets fname to NULL */
- torrc_fname = NULL;
+ *fname_var = NULL;
cf = tor_strdup("");
} else {
log(LOG_WARN, LD_CONFIG,
@@ -4332,7 +4466,7 @@ load_torrc_from_disk(int argc, char **argv)
return cf;
err:
tor_free(fname);
- torrc_fname = NULL;
+ *fname_var = NULL;
return NULL;
}
@@ -4343,7 +4477,7 @@ load_torrc_from_disk(int argc, char **argv)
int
options_init_from_torrc(int argc, char **argv)
{
- char *cf=NULL;
+ char *cf=NULL, *cf_defaults=NULL;
int i, retval, command;
static char **backup_argv;
static int backup_argc;
@@ -4403,13 +4537,15 @@ options_init_from_torrc(int argc, char **argv)
if (command == CMD_HASH_PASSWORD) {
cf = tor_strdup("");
} else {
- cf = load_torrc_from_disk(argc, argv);
+ cf_defaults = load_torrc_from_disk(argc, argv, 1);
+ cf = load_torrc_from_disk(argc, argv, 0);
if (!cf)
goto err;
}
- retval = options_init_from_string(cf, command, command_arg, &errmsg);
+ retval = options_init_from_string(cf_defaults, cf, command, command_arg, &errmsg);
tor_free(cf);
+ tor_free(cf_defaults);
if (retval < 0)
goto err;
@@ -4433,13 +4569,13 @@ options_init_from_torrc(int argc, char **argv)
* * -4 for error while setting the new options
*/
setopt_err_t
-options_init_from_string(const char *cf,
+options_init_from_string(const char *cf_defaults, const char *cf,
int command, const char *command_arg,
char **msg)
{
- or_options_t *oldoptions, *newoptions;
+ or_options_t *oldoptions, *newoptions, *newdefaultoptions=NULL;
config_line_t *cl;
- int retval;
+ int retval, i;
setopt_err_t err = SETOPT_ERR_MISC;
tor_assert(msg);
@@ -4452,17 +4588,24 @@ options_init_from_string(const char *cf,
newoptions->command = command;
newoptions->command_arg = command_arg;
- /* get config lines, assign them */
- retval = config_get_lines(cf, &cl);
- if (retval < 0) {
- err = SETOPT_ERR_PARSE;
- goto err;
- }
- retval = config_assign(&options_format, newoptions, cl, 0, 0, msg);
- config_free_lines(cl);
- if (retval < 0) {
- err = SETOPT_ERR_PARSE;
- goto err;
+ for (i = 0; i < 2; ++i) {
+ const char *body = i==0 ? cf_defaults : cf;
+ if (!body)
+ continue;
+ /* get config lines, assign them */
+ retval = config_get_lines(body, &cl, 1);
+ if (retval < 0) {
+ err = SETOPT_ERR_PARSE;
+ goto err;
+ }
+ retval = config_assign(&options_format, newoptions, cl, 0, 0, msg);
+ config_free_lines(cl);
+ if (retval < 0) {
+ err = SETOPT_ERR_PARSE;
+ goto err;
+ }
+ if (i==0)
+ newdefaultoptions = options_dup(&options_format, newoptions);
}
/* Go through command-line variables too */
@@ -4497,6 +4640,8 @@ options_init_from_string(const char *cf,
/* Clear newoptions and re-initialize them with new defaults. */
config_free(&options_format, newoptions);
+ config_free(&options_format, newdefaultoptions);
+ newdefaultoptions = NULL;
newoptions = tor_malloc_zero(sizeof(or_options_t));
newoptions->_magic = OR_OPTIONS_MAGIC;
options_init(newoptions);
@@ -4504,22 +4649,24 @@ options_init_from_string(const char *cf,
newoptions->command_arg = command_arg;
/* Assign all options a second time. */
- retval = config_get_lines(cf, &cl);
- if (retval < 0) {
- err = SETOPT_ERR_PARSE;
- goto err;
- }
- retval = config_assign(&options_format, newoptions, cl, 0, 0, msg);
- config_free_lines(cl);
- if (retval < 0) {
- err = SETOPT_ERR_PARSE;
- goto err;
- }
- retval = config_assign(&options_format, newoptions,
- global_cmdline_options, 0, 0, msg);
- if (retval < 0) {
- err = SETOPT_ERR_PARSE;
- goto err;
+ for (i = 0; i < 2; ++i) {
+ const char *body = i==0 ? cf_defaults : cf;
+ if (!body)
+ continue;
+ /* get config lines, assign them */
+ retval = config_get_lines(body, &cl, 1);
+ if (retval < 0) {
+ err = SETOPT_ERR_PARSE;
+ goto err;
+ }
+ retval = config_assign(&options_format, newoptions, cl, 0, 0, msg);
+ config_free_lines(cl);
+ if (retval < 0) {
+ err = SETOPT_ERR_PARSE;
+ goto err;
+ }
+ if (i==0)
+ newdefaultoptions = options_dup(&options_format, newoptions);
}
}
@@ -4538,11 +4685,14 @@ options_init_from_string(const char *cf,
err = SETOPT_ERR_SETTING;
goto err; /* frees and replaces old options */
}
+ config_free(&options_format, global_default_options);
+ global_default_options = newdefaultoptions;
return SETOPT_OK;
err:
config_free(&options_format, newoptions);
+ config_free(&options_format, newdefaultoptions);
if (*msg) {
char *old_msg = *msg;
tor_asprintf(msg, "Failed to parse/validate config: %s", old_msg);
@@ -4554,12 +4704,14 @@ options_init_from_string(const char *cf,
/** Return the location for our configuration file.
*/
const char *
-get_torrc_fname(void)
+get_torrc_fname(int defaults_fname)
{
- if (torrc_fname)
- return torrc_fname;
+ const char *fname = defaults_fname ? torrc_defaults_fname : torrc_fname;
+
+ if (fname)
+ return fname;
else
- return get_default_conf_file();
+ return get_default_conf_file(defaults_fname);
}
/** Adjust the address map based on the MapAddress elements in the
@@ -5164,7 +5316,7 @@ parse_dir_server_line(const char *line, dirinfo_type_t required_type,
* clause once Tor 0.1.2.17 is obsolete. */
log_warn(LD_CONFIG, "Dangerous dirserver line. To correct, erase your "
"torrc file (%s), or reinstall Tor and use the default torrc.",
- get_torrc_fname());
+ get_torrc_fname(0));
goto err;
}
if (base16_decode(digest, DIGEST_LEN, fingerprint, HEX_DIGEST_LEN)<0) {
@@ -5723,7 +5875,7 @@ options_save_current(void)
* If we try falling back to datadirectory or something, we have a better
* chance of saving the configuration, but a better chance of doing
* something the user never expected. */
- return write_configuration_file(get_torrc_fname(), get_options());
+ return write_configuration_file(get_torrc_fname(0), get_options());
}
/** Mapping from a unit name to a multiplier for converting that unit into a
@@ -6189,7 +6341,7 @@ or_state_load(void)
if (contents) {
config_line_t *lines=NULL;
int assign_retval;
- if (config_get_lines(contents, &lines)<0)
+ if (config_get_lines(contents, &lines, 0)<0)
goto done;
assign_retval = config_assign(&state_format, new_state,
lines, 0, 0, &errmsg);
@@ -6293,7 +6445,7 @@ or_state_save(time_t now)
tor_free(global_state->TorVersion);
tor_asprintf(&global_state->TorVersion, "Tor %s", get_version());
- state = config_dump(&state_format, global_state, 1, 0);
+ state = config_dump(&state_format, NULL, global_state, 1, 0);
format_local_iso_time(tbuf, now);
tor_asprintf(&contents,
"# Tor state file last generated on %s local time\n"
diff --git a/src/or/config.h b/src/or/config.h
index 76f6841d70..e1fc5cfe9a 100644
--- a/src/or/config.h
+++ b/src/or/config.h
@@ -23,24 +23,24 @@ const char *escaped_safe_str_client(const char *address);
const char *escaped_safe_str(const char *address);
const char *get_version(void);
-int config_get_lines(const char *string, config_line_t **result);
+int config_get_lines(const char *string, config_line_t **result, int extended);
void config_free_lines(config_line_t *front);
setopt_err_t options_trial_assign(config_line_t *list, int use_defaults,
int clear_first, char **msg);
int resolve_my_address(int warn_severity, const or_options_t *options,
uint32_t *addr, char **hostname_out);
-int is_local_addr(const tor_addr_t *addr) ATTR_PURE;
+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);
int options_init_from_torrc(int argc, char **argv);
-setopt_err_t options_init_from_string(const char *cf,
+setopt_err_t options_init_from_string(const char *cf_defaults, const char *cf,
int command, const char *command_arg, char **msg);
int option_is_recognized(const char *key);
const char *option_get_canonical_name(const char *key);
config_line_t *option_get_assignment(const or_options_t *options,
const char *key);
int options_save_current(void);
-const char *get_torrc_fname(void);
+const char *get_torrc_fname(int defaults_fname);
char *options_get_datadir_fname2_suffix(const or_options_t *options,
const char *sub1, const char *sub2,
const char *suffix);
diff --git a/src/or/connection.c b/src/or/connection.c
index a52bf48078..b87f922175 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -1318,6 +1318,24 @@ connection_connect(connection_t *conn, const char *address,
else
protocol_family = PF_INET;
+ if (get_options()->DisableNetwork) {
+ /* We should never even try to connect anyplace if DisableNetwork is set.
+ * Warn if we do, and refuse to make the connection. */
+ static ratelim_t disablenet_violated = RATELIM_INIT(30*60);
+ char *m;
+#ifdef MS_WINDOWS
+ *socket_error = WSAENETUNREACH;
+#else
+ *socket_error = ENETUNREACH;
+#endif
+ if ((m = rate_limit_log(&disablenet_violated, approx_time()))) {
+ log_warn(LD_BUG, "Tried to open a socket with DisableNetwork set.%s", m);
+ tor_free(m);
+ }
+ tor_fragile_assert();
+ return -1;
+ }
+
s = tor_open_socket(protocol_family,SOCK_STREAM,IPPROTO_TCP);
if (s < 0) {
*socket_error = tor_socket_errno(-1);
@@ -1968,7 +1986,7 @@ retry_all_listeners(smartlist_t *replaced_conns,
smartlist_add(listeners, conn);
} SMARTLIST_FOREACH_END(conn);
- if (! options->ClientOnly) {
+ if (! options->ClientOnly && ! options->DisableNetwork) {
if (retry_listeners(listeners,
CONN_TYPE_OR_LISTENER, options->ORListenAddress,
options->ORPort, "0.0.0.0",
@@ -1981,10 +1999,13 @@ retry_all_listeners(smartlist_t *replaced_conns,
retval = -1;
}
- if (retry_listener_ports(listeners,
- get_configured_client_ports(),
- new_conns) < 0)
- retval = -1;
+ if (!options->DisableNetwork) {
+ if (retry_listener_ports(listeners,
+ get_configured_client_ports(),
+ new_conns) < 0)
+ retval = -1;
+ }
+
if (retry_listeners(listeners,
CONN_TYPE_CONTROL_LISTENER,
options->ControlListenAddress,
@@ -2025,6 +2046,43 @@ retry_all_listeners(smartlist_t *replaced_conns,
return retval;
}
+/** Mark every listener of type other than CONTROL_LISTENER to be closed. */
+void
+connection_mark_all_noncontrol_listeners(void)
+{
+ SMARTLIST_FOREACH_BEGIN(get_connection_array(), connection_t *, conn) {
+ if (conn->marked_for_close)
+ continue;
+ if (conn->type == CONN_TYPE_CONTROL_LISTENER)
+ continue;
+ if (connection_is_listener(conn))
+ connection_mark_for_close(conn);
+ } SMARTLIST_FOREACH_END(conn);
+}
+
+/** Mark every external conection not used for controllers for close. */
+void
+connection_mark_all_noncontrol_connections(void)
+{
+ SMARTLIST_FOREACH_BEGIN(get_connection_array(), connection_t *, conn) {
+ if (conn->marked_for_close)
+ continue;
+ switch (conn->type) {
+ case CONN_TYPE_CPUWORKER:
+ case CONN_TYPE_CONTROL_LISTENER:
+ case CONN_TYPE_CONTROL:
+ break;
+ case CONN_TYPE_AP:
+ connection_mark_unattached_ap(TO_ENTRY_CONN(conn),
+ END_STREAM_REASON_HIBERNATING);
+ break;
+ default:
+ connection_mark_for_close(conn);
+ break;
+ }
+ } SMARTLIST_FOREACH_END(conn);
+}
+
/** Return 1 if we should apply rate limiting to <b>conn</b>, and 0
* otherwise.
* Right now this just checks if it's an internal IP address or an
diff --git a/src/or/connection.h b/src/or/connection.h
index 9f11489727..c4b8bf8abe 100644
--- a/src/or/connection.h
+++ b/src/or/connection.h
@@ -66,6 +66,9 @@ int get_proxy_addrport(tor_addr_t *addr, uint16_t *port, int *proxy_type,
int retry_all_listeners(smartlist_t *replaced_conns,
smartlist_t *new_conns);
+void connection_mark_all_noncontrol_listeners(void);
+void connection_mark_all_noncontrol_connections(void);
+
ssize_t connection_bucket_write_limit(connection_t *conn, time_t now);
int global_write_bucket_low(connection_t *conn, size_t attempt, int priority);
void connection_bucket_init(void);
diff --git a/src/or/connection_or.c b/src/or/connection_or.c
index cce99e4d65..246b08ad77 100644
--- a/src/or/connection_or.c
+++ b/src/or/connection_or.c
@@ -492,6 +492,9 @@ connection_or_about_to_close(or_connection_t *or_conn)
time_t now = time(NULL);
connection_t *conn = TO_CONN(or_conn);
+ if (or_conn->pending_action)
+ tor_cancel_libevent_action(or_conn->pending_action);
+
/* Remember why we're closing this connection. */
if (conn->state != OR_CONN_STATE_OPEN) {
/* Inform any pending (not attached) circs that they should
@@ -1146,10 +1149,6 @@ connection_or_tls_renegotiated_cb(tor_tls_t *tls, void *_conn)
or_connection_t *conn = _conn;
(void)tls;
- /* Don't invoke this again. */
- tor_tls_set_renegotiate_callback(tls, NULL, NULL);
- tor_tls_block_renegotiation(tls);
-
if (connection_tls_finish_handshake(conn) < 0) {
/* XXXX_TLS double-check that it's ok to do this from inside read. */
/* XXXX_TLS double-check that this verifies certificates. */
@@ -1157,6 +1156,34 @@ connection_or_tls_renegotiated_cb(tor_tls_t *tls, void *_conn)
}
}
+/*DOCDOC*/
+static void
+close_connection_libevent_cb(void *_conn)
+{
+ or_connection_t *or_conn = _conn;
+ connection_t *conn = TO_CONN(or_conn);
+
+ or_conn->pending_action = NULL;
+
+ connection_stop_reading(conn);
+ if (!conn->marked_for_close)
+ connection_mark_for_close(conn);
+}
+
+/* DOCDOC */
+static void
+connection_or_close_connection_cb(void *_conn)
+{
+ /* We can't close their connection from in here since it's an OpenSSL
+ callback, so we set a libevent event that triggers in the next event
+ loop and closes the connection. */
+ or_connection_t *or_conn = _conn;
+ if (or_conn->_base.marked_for_close || or_conn->pending_action)
+ return;
+ or_conn->pending_action =
+ tor_run_in_libevent_loop(close_connection_libevent_cb, or_conn);
+}
+
/** Move forward with the tls handshake. If it finishes, hand
* <b>conn</b> to connection_tls_finish_handshake().
*
@@ -1203,8 +1230,9 @@ connection_tls_continue_handshake(or_connection_t *conn)
/* v2/v3 handshake, but not a client. */
log_debug(LD_OR, "Done with initial SSL handshake (server-side). "
"Expecting renegotiation or VERSIONS cell");
- tor_tls_set_renegotiate_callback(conn->tls,
+ tor_tls_set_renegotiate_callbacks(conn->tls,
connection_or_tls_renegotiated_cb,
+ connection_or_close_connection_cb,
conn);
conn->_base.state = OR_CONN_STATE_TLS_SERVER_RENEGOTIATING;
connection_stop_writing(TO_CONN(conn));
@@ -1266,8 +1294,9 @@ connection_or_handle_event_cb(struct bufferevent *bufev, short event,
} else if (tor_tls_get_num_server_handshakes(conn->tls) == 1) {
/* v2 or v3 handshake, as a server. Only got one handshake, so
* wait for the next one. */
- tor_tls_set_renegotiate_callback(conn->tls,
+ tor_tls_set_renegotiate_callbacks(conn->tls,
connection_or_tls_renegotiated_cb,
+ connection_or_close_connection_cb,
conn);
conn->_base.state = OR_CONN_STATE_TLS_SERVER_RENEGOTIATING;
/* return 0; */
@@ -1536,7 +1565,6 @@ connection_tls_finish_handshake(or_connection_t *conn)
connection_or_init_conn_from_address(conn, &conn->_base.addr,
conn->_base.port, digest_rcvd, 0);
}
- tor_tls_block_renegotiation(conn->tls);
return connection_or_set_state_open(conn);
} else {
conn->_base.state = OR_CONN_STATE_OR_HANDSHAKING_V2;
diff --git a/src/or/control.c b/src/or/control.c
index 109eb8857b..8d924b44f1 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -737,7 +737,7 @@ control_setconf_helper(control_connection_t *conn, uint32_t len, char *body,
SMARTLIST_FOREACH(entries, char *, cp, tor_free(cp));
smartlist_free(entries);
- if (config_get_lines(config, &lines) < 0) {
+ if (config_get_lines(config, &lines, 0) < 0) {
log_warn(LD_CONTROL,"Controller gave us config lines we can't parse.");
connection_write_str_to_buf("551 Couldn't parse configuration\r\n",
conn);
@@ -883,7 +883,7 @@ handle_control_loadconf(control_connection_t *conn, uint32_t len,
const char *msg = NULL;
(void) len;
- retval = options_init_from_string(body, CMD_RUN_TOR, NULL, &errstring);
+ retval = options_init_from_string(NULL, body, CMD_RUN_TOR, NULL, &errstring);
if (retval != SETOPT_OK)
log_warn(LD_CONTROL,
@@ -1378,7 +1378,9 @@ getinfo_helper_misc(control_connection_t *conn, const char *question,
if (!strcmp(question, "version")) {
*answer = tor_strdup(get_version());
} else if (!strcmp(question, "config-file")) {
- *answer = tor_strdup(get_torrc_fname());
+ *answer = tor_strdup(get_torrc_fname(0));
+ } 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);
} else if (!strcmp(question, "info/names")) {
diff --git a/src/or/dirserv.c b/src/or/dirserv.c
index be62459b16..8fe1b18a35 100644
--- a/src/or/dirserv.c
+++ b/src/or/dirserv.c
@@ -232,7 +232,7 @@ dirserv_load_fingerprint_file(void)
}
tor_free(fname);
- result = config_get_lines(cf, &front);
+ result = config_get_lines(cf, &front, 0);
tor_free(cf);
if (result < 0) {
log_warn(LD_CONFIG, "Error reading from fingerprint file");
diff --git a/src/or/dirvote.c b/src/or/dirvote.c
index bf34c62af3..01e2358c44 100644
--- a/src/or/dirvote.c
+++ b/src/or/dirvote.c
@@ -50,7 +50,7 @@ static int dirvote_publish_consensus(void);
static char *make_consensus_method_list(int low, int high, const char *sep);
/** The highest consensus method that we currently support. */
-#define MAX_SUPPORTED_CONSENSUS_METHOD 11
+#define MAX_SUPPORTED_CONSENSUS_METHOD 12
/** Lowest consensus method that contains a 'directory-footer' marker */
#define MIN_METHOD_FOR_FOOTER 9
@@ -64,6 +64,10 @@ static char *make_consensus_method_list(int low, int high, const char *sep);
/** Lowest consensus method that generates microdescriptors */
#define MIN_METHOD_FOR_MICRODESC 8
+/** Lowest consensus method that ensures a majority of authorities voted
+ * for a param. */
+#define MIN_METHOD_FOR_MAJORITY_PARAMS 12
+
/* =====
* Voting
* =====*/
@@ -608,11 +612,16 @@ compute_consensus_versions_list(smartlist_t *lst, int n_versioning)
return result;
}
+/** Minimum number of directory authorities voting for a parameter to
+ * include it in the consensus, if consensus method 12 or later is to be
+ * used. See proposal 178 for details. */
+#define MIN_VOTES_FOR_PARAM 3
+
/** Helper: given a list of valid networkstatus_t, return a new string
* containing the contents of the consensus network parameter set.
*/
/* private */ char *
-dirvote_compute_params(smartlist_t *votes)
+dirvote_compute_params(smartlist_t *votes, int method, int total_authorities)
{
int i;
int32_t *vals;
@@ -669,11 +678,17 @@ dirvote_compute_params(smartlist_t *votes)
next_param = smartlist_get(param_list, param_sl_idx+1);
if (!next_param || strncmp(next_param, param, cur_param_len)) {
/* We've reached the end of a series. */
- int32_t median = median_int32(vals, i);
- char *out_string = tor_malloc(64+cur_param_len);
- memcpy(out_string, param, cur_param_len);
- tor_snprintf(out_string+cur_param_len,64, "%ld", (long)median);
- smartlist_add(output, out_string);
+ /* Make sure enough authorities voted on this param, unless the
+ * the consensus method we use is too old for that. */
+ if (method < MIN_METHOD_FOR_MAJORITY_PARAMS ||
+ i > total_authorities/2 ||
+ i >= MIN_VOTES_FOR_PARAM) {
+ int32_t median = median_int32(vals, i);
+ char *out_string = tor_malloc(64+cur_param_len);
+ memcpy(out_string, param, cur_param_len);
+ tor_snprintf(out_string+cur_param_len,64, "%ld", (long)median);
+ smartlist_add(output, out_string);
+ }
i = 0;
if (next_param) {
@@ -1496,7 +1511,8 @@ networkstatus_compute_consensus(smartlist_t *votes,
}
if (consensus_method >= MIN_METHOD_FOR_PARAMS) {
- params = dirvote_compute_params(votes);
+ params = dirvote_compute_params(votes, consensus_method,
+ total_authorities);
if (params) {
smartlist_add(chunks, tor_strdup("params "));
smartlist_add(chunks, params);
diff --git a/src/or/dirvote.h b/src/or/dirvote.h
index d19635173f..1f4dc362b5 100644
--- a/src/or/dirvote.h
+++ b/src/or/dirvote.h
@@ -84,7 +84,8 @@ document_signature_t *voter_get_sig_by_algorithm(
#ifdef DIRVOTE_PRIVATE
char *format_networkstatus_vote(crypto_pk_env_t *private_key,
networkstatus_t *v3_ns);
-char *dirvote_compute_params(smartlist_t *votes);
+char *dirvote_compute_params(smartlist_t *votes, int method,
+ int total_authorities);
#endif
#endif
diff --git a/src/or/dns.c b/src/or/dns.c
index 8ed9536903..beb110acb2 100644
--- a/src/or/dns.c
+++ b/src/or/dns.c
@@ -1395,6 +1395,10 @@ launch_resolve(edge_connection_t *exitconn)
int r;
int options = get_options()->ServerDNSSearchDomains ? 0
: DNS_QUERY_NO_SEARCH;
+
+ if (get_options()->DisableNetwork)
+ return -1;
+
/* What? Nameservers not configured? Sounds like a bug. */
if (!nameservers_configured) {
log_warn(LD_EXIT, "(Harmless.) Nameservers not configured, but resolve "
@@ -1601,6 +1605,9 @@ launch_test_addresses(int fd, short event, void *args)
(void)event;
(void)args;
+ if (options->DisableNetwork)
+ return;
+
log_info(LD_EXIT, "Launching checks to see whether our nameservers like to "
"hijack *everything*.");
/* This situation is worse than the failure-hijacking situation. When this
diff --git a/src/or/hibernate.c b/src/or/hibernate.c
index 6fd2b4f197..ce64581d1c 100644
--- a/src/or/hibernate.c
+++ b/src/or/hibernate.c
@@ -735,7 +735,6 @@ hibernate_soft_limit_reached(void)
static void
hibernate_begin(hibernate_state_t new_state, time_t now)
{
- connection_t *conn;
const or_options_t *options = get_options();
if (new_state == HIBERNATE_STATE_EXITING &&
@@ -756,15 +755,7 @@ hibernate_begin(hibernate_state_t new_state, time_t now)
}
/* close listeners. leave control listener(s). */
- while ((conn = connection_get_by_type(CONN_TYPE_OR_LISTENER)) ||
- (conn = connection_get_by_type(CONN_TYPE_AP_LISTENER)) ||
- (conn = connection_get_by_type(CONN_TYPE_AP_TRANS_LISTENER)) ||
- (conn = connection_get_by_type(CONN_TYPE_AP_DNS_LISTENER)) ||
- (conn = connection_get_by_type(CONN_TYPE_AP_NATD_LISTENER)) ||
- (conn = connection_get_by_type(CONN_TYPE_DIR_LISTENER))) {
- log_info(LD_NET,"Closing listener type %d", conn->type);
- connection_mark_for_close(conn);
- }
+ connection_mark_all_noncontrol_listeners();
/* XXX kill intro point circs */
/* XXX upload rendezvous service descriptors with no intro points */
diff --git a/src/or/main.c b/src/or/main.c
index 95f9958aa8..da45f5a681 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -196,6 +196,26 @@ free_old_inbuf(connection_t *conn)
}
#endif
+#ifdef MS_WINDOWS
+/** Remove the kernel-space send and receive buffers for <b>s</b>. For use
+ * with IOCP only. */
+static int
+set_buffer_lengths_to_zero(tor_socket_t s)
+{
+ int zero = 0;
+ int r = 0;
+ if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, (void*)&zero, sizeof(zero))) {
+ log_warn(LD_NET, "Unable to clear SO_SNDBUF");
+ r = -1;
+ }
+ if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, (void*)&zero, sizeof(zero))) {
+ log_warn(LD_NET, "Unable to clear SO_RCVBUF");
+ r = -1;
+ }
+ return r;
+}
+#endif
+
/** Add <b>conn</b> to the array of connections that we can poll on. The
* connection's socket must be set; the connection starts out
* non-reading and non-writing.
@@ -216,6 +236,14 @@ connection_add_impl(connection_t *conn, int is_connecting)
#ifdef USE_BUFFEREVENTS
if (connection_type_uses_bufferevent(conn)) {
if (SOCKET_OK(conn->s) && !conn->linked) {
+
+#ifdef MS_WINDOWS
+ if (tor_libevent_using_iocp_bufferevents() &&
+ get_options()->UserspaceIOCPBuffers) {
+ set_buffer_lengths_to_zero(conn->s);
+ }
+#endif
+
conn->bufev = bufferevent_socket_new(
tor_libevent_get_base(),
conn->s,
@@ -906,7 +934,7 @@ directory_info_has_arrived(time_t now, int from_cache)
update_extrainfo_downloads(now);
}
- if (server_mode(options) && !we_are_hibernating() && !from_cache &&
+ if (server_mode(options) && !net_is_disabled() && !from_cache &&
(can_complete_circuit || !any_predicted_circuits(now)))
consider_testing_reachability(1, 1);
}
@@ -1133,11 +1161,11 @@ run_scheduled_events(time_t now)
if (router_rebuild_descriptor(1)<0) {
log_info(LD_CONFIG, "Couldn't rebuild router descriptor");
}
- if (advertised_server_mode())
+ if (advertised_server_mode() & !options->DisableNetwork)
router_upload_dir_desc_to_dirservers(0);
}
- if (time_to_try_getting_descriptors < now) {
+ if (!options->DisableNetwork && time_to_try_getting_descriptors < now) {
update_all_descriptor_downloads(now);
update_extrainfo_downloads(now);
if (router_have_minimum_dir_info())
@@ -1188,7 +1216,7 @@ run_scheduled_events(time_t now)
if (time_to_launch_reachability_tests < now &&
(authdir_mode_tests_reachability(options)) &&
- !we_are_hibernating()) {
+ !net_is_disabled()) {
time_to_launch_reachability_tests = now + REACHABILITY_TEST_INTERVAL;
/* try to determine reachability of the other Tor relays */
dirserv_test_reachability(now);
@@ -1324,7 +1352,7 @@ run_scheduled_events(time_t now)
/* 2b. Once per minute, regenerate and upload the descriptor if the old
* one is inaccurate. */
- if (time_to_check_descriptor < now) {
+ if (time_to_check_descriptor < now && !options->DisableNetwork) {
static int dirport_reachability_count = 0;
time_to_check_descriptor = now + CHECK_DESCRIPTOR_INTERVAL;
check_descriptor_bandwidth_changed(now);
@@ -1399,7 +1427,7 @@ run_scheduled_events(time_t now)
connection_expire_held_open();
/** 3d. And every 60 seconds, we relaunch listeners if any died. */
- if (!we_are_hibernating() && time_to_check_listeners < now) {
+ if (!net_is_disabled() && time_to_check_listeners < now) {
retry_all_listeners(NULL, NULL);
time_to_check_listeners = now+60;
}
@@ -1410,7 +1438,7 @@ run_scheduled_events(time_t now)
* and we make a new circ if there are no clean circuits.
*/
have_dir_info = router_have_minimum_dir_info();
- if (have_dir_info && !we_are_hibernating())
+ if (have_dir_info && !net_is_disabled())
circuit_build_needed_circs(now);
/* every 10 seconds, but not at the same second as other such events */
@@ -1441,7 +1469,7 @@ run_scheduled_events(time_t now)
circuit_close_all_marked();
/** 7. And upload service descriptors if necessary. */
- if (can_complete_circuit && !we_are_hibernating()) {
+ if (can_complete_circuit && !net_is_disabled()) {
rend_consider_services_upload(now);
rend_consider_descriptor_republication();
}
@@ -1458,7 +1486,8 @@ run_scheduled_events(time_t now)
/** 9. and if we're a server, check whether our DNS is telling stories to
* us. */
- if (public_server_mode(options) && time_to_check_for_correct_dns < now) {
+ if (!net_is_disabled() &&
+ public_server_mode(options) && time_to_check_for_correct_dns < now) {
if (!time_to_check_for_correct_dns) {
time_to_check_for_correct_dns = now + 60 + crypto_rand_int(120);
} else {
@@ -1477,7 +1506,8 @@ run_scheduled_events(time_t now)
}
/** 11. check the port forwarding app */
- if (time_to_check_port_forwarding < now &&
+ if (!net_is_disabled() &&
+ time_to_check_port_forwarding < now &&
options->PortForwarding &&
is_server) {
#define PORT_FORWARDING_CHECK_INTERVAL 5
@@ -1489,7 +1519,7 @@ run_scheduled_events(time_t now)
}
/** 11b. check pending unconfigured managed proxies */
- if (pt_proxies_configuration_pending())
+ if (!net_is_disabled() && pt_proxies_configuration_pending())
pt_configure_remaining_proxies();
/** 11c. validate pluggable transports configuration if we need to */
@@ -1561,7 +1591,7 @@ second_elapsed_callback(periodic_timer_t *timer, void *arg)
control_event_stream_bandwidth_used();
if (server_mode(options) &&
- !we_are_hibernating() &&
+ !net_is_disabled() &&
seconds_elapsed > 0 &&
can_complete_circuit &&
stats_n_seconds_working / TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT !=
@@ -1762,7 +1792,8 @@ do_hup(void)
/* retry appropriate downloads */
router_reset_status_download_failures();
router_reset_descriptor_download_failures();
- update_networkstatus_downloads(time(NULL));
+ if (!options->DisableNetwork)
+ update_networkstatus_downloads(time(NULL));
/* We'll retry routerstatus downloads in about 10 seconds; no need to
* force a retry there. */
diff --git a/src/or/or.h b/src/or/or.h
index ec49014d94..be7fb413e2 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -1272,6 +1272,8 @@ typedef struct or_connection_t {
unsigned active_circuit_pqueue_last_recalibrated;
struct or_connection_t *next_with_same_id; /**< Next connection with same
* identity digest as this one. */
+
+ tor_libevent_action_t *pending_action;
} or_connection_t;
/** Subtype of connection_t for an "edge connection" -- that is, an entry (ap)
@@ -2836,11 +2838,25 @@ typedef struct port_cfg_t {
char unix_addr[FLEXIBLE_ARRAY_MEMBER];
} port_cfg_t;
+/** Ordinary configuration line. */
+#define CONFIG_LINE_NORMAL 0
+/** Appends to previous configuration for the same option, even if we
+ * would ordinary replace it. */
+#define CONFIG_LINE_APPEND 1
+/* Removes all previous configuration for an option. */
+#define CONFIG_LINE_CLEAR 2
+
/** A linked list of lines in a config file. */
typedef struct config_line_t {
char *key;
char *value;
struct config_line_t *next;
+ /** What special treatment (if any) does this line require? */
+ unsigned int command:2;
+ /** If true, subsequent assignments to this linelist should replace
+ * it, not extend it. Set only on the first item in a linelist in an
+ * or_options_t. */
+ unsigned int fragile:1;
} config_line_t;
typedef struct routerset_t routerset_t;
@@ -3250,6 +3266,8 @@ typedef struct {
disclaimer. This allows a server administrator to show
that they're running Tor and anyone visiting their server
will know this without any specialized knowledge. */
+ int DisableDebuggerAttachment; /**< Currently Linux only specific attempt to
+ disable ptrace; needs BSD testing. */
/** Boolean: if set, we start even if our resolv.conf file is missing
* or broken. */
int ServerDNSAllowBrokenConfig;
@@ -3434,6 +3452,15 @@ typedef struct {
* never use it. If -1, we do what the consensus says. */
int OptimisticData;
+ /** If 1, and we are using IOCP, we set the kernel socket SNDBUF and RCVBUF
+ * to 0 to try to save kernel memory and avoid the dread "Out of buffers"
+ * issue. */
+ int UserspaceIOCPBuffers;
+
+ /** If 1, we accept and launch no external network connections, except on
+ * control ports. */
+ int DisableNetwork;
+
} or_options_t;
/** Persistent state for an onion router, as saved to disk. */
diff --git a/src/or/router.c b/src/or/router.c
index 5d36939a8b..8fe45dd6f8 100644
--- a/src/or/router.c
+++ b/src/or/router.c
@@ -785,7 +785,7 @@ check_whether_dirport_reachable(void)
const or_options_t *options = get_options();
return !options->DirPort ||
options->AssumeReachable ||
- we_are_hibernating() ||
+ net_is_disabled() ||
can_reach_dir_port;
}
@@ -811,7 +811,7 @@ decide_to_advertise_dirport(const or_options_t *options, uint16_t dir_port)
return 0;
if (authdir_mode(options)) /* always publish */
return dir_port;
- if (we_are_hibernating())
+ if (net_is_disabled())
return 0;
if (!check_whether_dirport_reachable())
return 0;
@@ -979,6 +979,14 @@ router_perform_bandwidth_test(int num_circs, time_t now)
}
}
+/** Return true iff our network is in some sense disabled: either we're
+ * hibernating, entering hibernation, or */
+int
+net_is_disabled(void)
+{
+ return get_options()->DisableNetwork || we_are_hibernating();
+}
+
/** Return true iff we believe ourselves to be an authoritative
* directory server.
*/
diff --git a/src/or/router.h b/src/or/router.h
index 68eadbf4c2..6a9851cdbd 100644
--- a/src/or/router.h
+++ b/src/or/router.h
@@ -40,6 +40,8 @@ void router_orport_found_reachable(void);
void router_dirport_found_reachable(void);
void router_perform_bandwidth_test(int num_circs, time_t now);
+int net_is_disabled(void);
+
int authdir_mode(const or_options_t *options);
int authdir_mode_v1(const or_options_t *options);
int authdir_mode_v2(const or_options_t *options);
diff --git a/src/or/routerlist.c b/src/or/routerlist.c
index d97b978f43..689df99c57 100644
--- a/src/or/routerlist.c
+++ b/src/or/routerlist.c
@@ -3244,7 +3244,7 @@ router_set_status(const char *digest, int up)
log_debug(LD_DIR,"Marking router %s as %s.",
node_describe(node), up ? "up" : "down");
#endif
- if (!up && node_is_me(node) && !we_are_hibernating())
+ if (!up && node_is_me(node) && !net_is_disabled())
log_warn(LD_NET, "We just marked ourself as down. Are your external "
"addresses reachable?");
node->is_running = up;
@@ -4009,6 +4009,8 @@ signed_desc_digest_is_recognized(signed_descriptor_t *desc)
void
update_all_descriptor_downloads(time_t now)
{
+ if (get_options()->DisableNetwork)
+ return;
update_router_descriptor_downloads(now);
update_microdesc_downloads(now);
launch_dummy_descriptor_download_as_needed(now, get_options());
@@ -4021,6 +4023,8 @@ routerlist_retry_directory_downloads(time_t now)
{
router_reset_status_download_failures();
router_reset_descriptor_download_failures();
+ if (get_options()->DisableNetwork)
+ return;
update_networkstatus_downloads(now);
update_all_descriptor_downloads(now);
}
diff --git a/src/or/transports.c b/src/or/transports.c
index 6e8200f407..10155c4475 100644
--- a/src/or/transports.c
+++ b/src/or/transports.c
@@ -13,11 +13,18 @@
#include "transports.h"
#include "util.h"
-static void set_managed_proxy_environment(char ***envp,
+#ifdef MS_WINDOWS
+static void set_managed_proxy_environment(LPVOID *envp,
const managed_proxy_t *mp);
+#else
+static int set_managed_proxy_environment(char ***envp,
+ const managed_proxy_t *mp);
+#endif
+
static INLINE int proxy_configuration_finished(const managed_proxy_t *mp);
-static void managed_proxy_destroy(managed_proxy_t *mp);
+static void managed_proxy_destroy(managed_proxy_t *mp,
+ int also_terminate_process);
static void handle_finished_proxy(managed_proxy_t *mp);
static void configure_proxy(managed_proxy_t *mp);
@@ -229,12 +236,10 @@ proxy_prepare_for_restart(managed_proxy_t *mp)
transport_t *t_tmp = NULL;
tor_assert(mp->conf_state == PT_PROTO_COMPLETED);
- tor_assert(mp->pid);
- /* kill the old obfsproxy process */
- tor_terminate_process(mp->pid);
- mp->pid = 0;
- fclose(mp->_stdout);
+ /* destroy the process handle and terminate the process. */
+ tor_process_handle_destroy(mp->process_handle, 1);
+ mp->process_handle = NULL;
/* destroy all its old transports. we no longer use them. */
SMARTLIST_FOREACH_BEGIN(mp->transports, const char *, t_name) {
@@ -256,52 +261,52 @@ proxy_prepare_for_restart(managed_proxy_t *mp)
static int
launch_managed_proxy(managed_proxy_t *mp)
{
- (void) mp;
- (void) set_managed_proxy_environment;
- return -1;
-#if 0
- /* XXXX023 we must reenable this code for managed proxies to work.
- * "All it needs" is revision to work with the new tor_spawn_background
- * API. */
- char **envp=NULL;
- int pid;
- process_handle_t proc;
- FILE *stdout_read = NULL;
- int stdout_pipe=-1, stderr_pipe=-1;
+ int retval;
+
+#ifdef MS_WINDOWS
+
+ LPVOID envp=NULL;
- /* prepare the environment variables for the managed proxy */
set_managed_proxy_environment(&envp, mp);
+ tor_assert(envp);
- pid = tor_spawn_background(mp->argv[0], (const char **)mp->argv,
- (const char **)envp, &proc);
- if (pid < 0) {
- log_warn(LD_GENERAL, "Managed proxy at '%s' failed at launch.",
- mp->argv[0]);
+ /* Passing NULL as lpApplicationName makes Windows search for the .exe */
+ retval = tor_spawn_background(NULL, (const char **)mp->argv, envp,
+ &mp->process_handle);
+
+ tor_free(envp);
+
+#else
+
+ char **envp=NULL;
+
+ /* prepare the environment variables for the managed proxy */
+ if (set_managed_proxy_environment(&envp, mp) < 0) {
+ log_warn(LD_GENERAL, "Could not setup the environment of "
+ "the managed proxy at '%s'.", mp->argv[0]);
+ free_execve_args(envp);
return -1;
}
+ retval = tor_spawn_background(mp->argv[0], (const char **)mp->argv,
+ (const char **)envp, &mp->process_handle);
+
/* free the memory allocated by set_managed_proxy_environment(). */
free_execve_args(envp);
- /* Set stdout/stderr pipes to be non-blocking */
-#ifdef _WIN32
- {
- u_long nonblocking = 1;
- ioctlsocket(stdout_pipe, FIONBIO, &nonblocking);
- }
-#else
- fcntl(stdout_pipe, F_SETFL, O_NONBLOCK);
#endif
- /* Open the buffered IO streams */
- stdout_read = fdopen(stdout_pipe, "r");
+ if (retval == PROCESS_STATUS_ERROR) {
+ log_warn(LD_GENERAL, "Managed proxy at '%s' failed at launch.",
+ mp->argv[0]);
+ return -1;
+ }
- log_info(LD_CONFIG, "Managed proxy has spawned at PID %d.", pid);
+ log_info(LD_CONFIG, "Managed proxy at '%s' has spawned with PID '%d'.",
+ mp->argv[0], tor_process_get_pid(mp->process_handle));
mp->conf_state = PT_PROTO_LAUNCHED;
- mp->_stdout = stdout_read;
- mp->pid = pid;
-#endif
+
return 0;
}
@@ -314,7 +319,8 @@ pt_configure_remaining_proxies(void)
log_debug(LD_CONFIG, "Configuring remaining managed proxies (%d)!",
unconfigured_proxies_n);
SMARTLIST_FOREACH_BEGIN(managed_proxy_list, managed_proxy_t *, mp) {
- tor_assert(mp->conf_state != PT_PROTO_BROKEN);
+ tor_assert(mp->conf_state != PT_PROTO_BROKEN ||
+ mp->conf_state != PT_PROTO_FAILED_LAUNCH);
if (mp->got_hup) {
mp->got_hup = 0;
@@ -343,6 +349,65 @@ pt_configure_remaining_proxies(void)
} SMARTLIST_FOREACH_END(mp);
}
+#ifdef MS_WINDOWS
+
+/** Attempt to continue configuring managed proxy <b>mp</b>. */
+static void
+configure_proxy(managed_proxy_t *mp)
+{
+ int pos;
+ char stdout_buf[200];
+ smartlist_t *lines = NULL;
+
+ /* if we haven't launched the proxy yet, do it now */
+ if (mp->conf_state == PT_PROTO_INFANT) {
+ if (launch_managed_proxy(mp) < 0) { /* launch fail */
+ mp->conf_state = PT_PROTO_FAILED_LAUNCH;
+ handle_finished_proxy(mp);
+ }
+ return;
+ }
+
+ tor_assert(mp->conf_state != PT_PROTO_INFANT);
+ tor_assert(mp->process_handle);
+
+ pos = tor_read_all_handle(tor_process_get_stdout_pipe(mp->process_handle),
+ stdout_buf, sizeof(stdout_buf) - 1, NULL);
+ if (pos < 0) {
+ log_notice(LD_GENERAL, "Failed to read data from managed proxy");
+ mp->conf_state = PT_PROTO_BROKEN;
+ goto done;
+ }
+
+ if (pos == 0) /* proxy has nothing interesting to say. */
+ return;
+
+ /* End with a null even if there isn't a \r\n at the end */
+ /* TODO: What if this is a partial line? */
+ stdout_buf[pos] = '\0';
+
+ /* Split up the buffer */
+ lines = smartlist_create();
+ tor_split_lines(lines, stdout_buf, pos);
+
+ /* Handle lines. */
+ SMARTLIST_FOREACH_BEGIN(lines, const char *, line) {
+ handle_proxy_line(line, mp);
+ if (proxy_configuration_finished(mp))
+ goto done;
+ } SMARTLIST_FOREACH_END(line);
+
+ done:
+ /* if the proxy finished configuring, exit the loop. */
+ if (proxy_configuration_finished(mp))
+ handle_finished_proxy(mp);
+
+ if (lines)
+ smartlist_free(lines);
+}
+
+#else /* MS_WINDOWS */
+
/** Attempt to continue configuring managed proxy <b>mp</b>. */
static void
configure_proxy(managed_proxy_t *mp)
@@ -352,15 +417,19 @@ configure_proxy(managed_proxy_t *mp)
/* if we haven't launched the proxy yet, do it now */
if (mp->conf_state == PT_PROTO_INFANT) {
- launch_managed_proxy(mp);
+ if (launch_managed_proxy(mp) < 0) { /* launch fail */
+ mp->conf_state = PT_PROTO_FAILED_LAUNCH;
+ handle_finished_proxy(mp);
+ }
return;
}
tor_assert(mp->conf_state != PT_PROTO_INFANT);
+ tor_assert(mp->process_handle);
while (1) {
- r = get_string_from_pipe(mp->_stdout, stdout_buf,
- sizeof(stdout_buf) - 1);
+ r = get_string_from_pipe(tor_process_get_stdout_pipe(mp->process_handle),
+ stdout_buf, sizeof(stdout_buf) - 1);
if (r == IO_STREAM_OKAY) { /* got a line; handle it! */
handle_proxy_line((const char *)stdout_buf, mp);
@@ -382,6 +451,8 @@ configure_proxy(managed_proxy_t *mp)
}
}
+#endif /* MS_WINDOWS */
+
/** Register server managed proxy <b>mp</b> transports to state */
static void
register_server_proxy(managed_proxy_t *mp)
@@ -394,6 +465,10 @@ register_server_proxy(managed_proxy_t *mp)
tor_assert(mp->conf_state != PT_PROTO_COMPLETED);
SMARTLIST_FOREACH_BEGIN(mp->transports, transport_t *, t) {
save_transport_to_state(t->name, &t->addr, t->port);
+ /* LOG_WARN so that the bridge operator can easily find the
+ transport's port in the log file and send it to the users. */
+ log_warn(LD_GENERAL, "Registered server transport '%s' at '%s:%d'",
+ t->name, fmt_addr(&t->addr), (int)t->port);
smartlist_add(sm_tmp, tor_strdup(t->name));
} SMARTLIST_FOREACH_END(t);
@@ -453,7 +528,8 @@ register_proxy(managed_proxy_t *mp)
/** Free memory allocated by managed proxy <b>mp</b>. */
static void
-managed_proxy_destroy(managed_proxy_t *mp)
+managed_proxy_destroy(managed_proxy_t *mp,
+ int also_terminate_process)
{
if (mp->conf_state != PT_PROTO_COMPLETED)
SMARTLIST_FOREACH(mp->transports, transport_t *, t, transport_free(t));
@@ -470,15 +546,11 @@ managed_proxy_destroy(managed_proxy_t *mp)
/* remove it from the list of managed proxies */
smartlist_remove(managed_proxy_list, mp);
- /* close its stdout stream */
- if (mp->_stdout)
- fclose(mp->_stdout);
-
/* free the argv */
free_execve_args(mp->argv);
- if (mp->pid)
- tor_terminate_process(mp->pid);
+ tor_process_handle_destroy(mp->process_handle, also_terminate_process);
+ mp->process_handle = NULL;
tor_free(mp);
}
@@ -489,7 +561,10 @@ handle_finished_proxy(managed_proxy_t *mp)
{
switch (mp->conf_state) {
case PT_PROTO_BROKEN: /* if broken: */
- managed_proxy_destroy(mp); /* annihilate it. */
+ managed_proxy_destroy(mp, 1); /* annihilate it. */
+ break;
+ case PT_PROTO_FAILED_LAUNCH: /* if it failed before launching: */
+ managed_proxy_destroy(mp, 0); /* destroy it but don't terminate */
break;
case PT_PROTO_CONFIGURED: /* if configured correctly: */
register_proxy(mp); /* register its transports */
@@ -515,7 +590,8 @@ static INLINE int
proxy_configuration_finished(const managed_proxy_t *mp)
{
return (mp->conf_state == PT_PROTO_CONFIGURED ||
- mp->conf_state == PT_PROTO_BROKEN);
+ mp->conf_state == PT_PROTO_BROKEN ||
+ mp->conf_state == PT_PROTO_FAILED_LAUNCH);
}
/** This function is called when a proxy sends an {S,C}METHODS DONE message. */
@@ -537,7 +613,7 @@ handle_methods_done(const managed_proxy_t *mp)
void
handle_proxy_line(const char *line, managed_proxy_t *mp)
{
- log_debug(LD_GENERAL, "Got a line from managed proxy: %s\n", line);
+ log_debug(LD_GENERAL, "Got a line from managed proxy: %s", line);
if (strlen(line) < SMALLEST_MANAGED_LINE_SIZE) {
log_warn(LD_GENERAL, "Managed proxy configuration line is too small. "
@@ -614,14 +690,16 @@ handle_proxy_line(const char *line, managed_proxy_t *mp)
return;
} else if (!strcmpstart(line, SPAWN_ERROR_MESSAGE)) {
log_warn(LD_GENERAL, "Could not launch managed proxy executable!");
- goto err;
+ mp->conf_state = PT_PROTO_FAILED_LAUNCH;
+ return;
}
log_warn(LD_CONFIG, "Unknown line received by managed proxy. (%s)", line);
err:
mp->conf_state = PT_PROTO_BROKEN;
- return;
+ log_warn(LD_CONFIG, "Managed proxy at '%s' failed the configuration protocol"
+ " and will be destroyed.", mp->argv ? mp->argv[0] : "");
}
/** Parses an ENV-ERROR <b>line</b> and warns the user accordingly. */
@@ -858,8 +936,115 @@ get_bindaddr_for_proxy(const managed_proxy_t *mp)
return bindaddr;
}
-/** Prepare the <b>envp</b> of managed proxy <b>mp</b> */
+#ifdef MS_WINDOWS
+
+/** Prepare the environment <b>envp</b> of managed proxy <b>mp</b>.
+ * <b>envp</b> is allocated on the heap and should be freed by the
+ * caller after its use. */
static void
+set_managed_proxy_environment(LPVOID *envp, const managed_proxy_t *mp)
+{
+ const or_options_t *options = get_options();
+ extern char **environ;
+
+ LPVOID tmp=NULL;
+
+ char *state_tmp=NULL;
+ char *state_env=NULL;
+ char *transports_to_launch=NULL;
+ char *transports_env=NULL;
+ char *bindaddr_tmp=NULL;
+ char *bindaddr_env=NULL;
+ char *orport_env=NULL;
+
+ char version_env[31]; /* XXX temp */
+ char extended_env[43]; /* XXX temp */
+
+ int env_size = 0;
+
+ /* A smartlist carrying all the env. variables that the managed
+ proxy should inherit. */
+ smartlist_t *envs = smartlist_create();
+
+ /* Copy the whole environment of the Tor process.
+ It should also copy PATH and HOME of the Tor process.*/
+ char **environ_tmp = environ;
+ while (*environ_tmp)
+ smartlist_add(envs, *environ_tmp++);
+
+ /* Create the TOR_PT_* environment variables. */
+ state_tmp = get_datadir_fname("pt_state/"); /* XXX temp */
+ tor_asprintf(&state_env, "TOR_PT_STATE_LOCATION=%s", state_tmp);
+
+ strcpy(version_env, "TOR_PT_MANAGED_TRANSPORT_VER=1");
+
+ transports_to_launch =
+ smartlist_join_strings(mp->transports_to_launch, ",", 0, NULL);
+
+ tor_asprintf(&transports_env,
+ mp->is_server ?
+ "TOR_PT_SERVER_TRANSPORTS=%s" : "TOR_PT_CLIENT_TRANSPORTS=%s",
+ transports_to_launch);
+
+ smartlist_add(envs, state_env);
+ smartlist_add(envs, version_env);
+ smartlist_add(envs, transports_env);
+
+ if (mp->is_server) {
+ tor_asprintf(&orport_env, "TOR_PT_ORPORT=127.0.0.1:%d", options->ORPort);
+
+ bindaddr_tmp = get_bindaddr_for_proxy(mp);
+ tor_asprintf(&bindaddr_env, "TOR_PT_SERVER_BINDADDR=%s", bindaddr_tmp);
+
+ strcpy(extended_env, "TOR_PT_EXTENDED_SERVER_PORT=127.0.0.1:4200");
+
+ smartlist_add(envs, orport_env);
+ smartlist_add(envs, extended_env);
+ smartlist_add(envs, bindaddr_env);
+ }
+
+ /* It seems like some versions of Windows need a sorted lpEnvironment
+ block. */
+ smartlist_sort_strings(envs);
+
+ /* An environment block consists of a null-terminated block of
+ null-terminated strings: */
+
+ /* Calculate the block's size. */
+ SMARTLIST_FOREACH(envs, const char *, s,
+ env_size += strlen(s) + 1);
+ env_size += 1; /* space for last NUL */
+
+ *envp = tor_malloc(env_size);
+ tmp = *envp;
+
+ /* Create the block. */
+ SMARTLIST_FOREACH_BEGIN(envs, const char *, s) {
+ memcpy(tmp, s, strlen(s)); /* copy the env. variable string */
+ tmp += strlen(s);
+ memset(tmp, '\0', 1); /* append NUL at the end of the string */
+ tmp += 1;
+ } SMARTLIST_FOREACH_END(s);
+ memset(tmp, '\0', 1); /* last NUL */
+
+ /* Finally, free the whole mess. */
+ tor_free(state_tmp);
+ tor_free(state_env);
+ tor_free(transports_to_launch);
+ tor_free(transports_env);
+ tor_free(bindaddr_tmp);
+ tor_free(bindaddr_env);
+ tor_free(orport_env);
+
+ smartlist_free(envs);
+}
+
+#else /* MS_WINDOWS */
+
+/** Prepare the environment <b>envp</b> of managed proxy <b>mp</b>.
+ * <b>envp</b> is allocated on the heap and should be freed by the
+ * caller after its use. */
+static int
set_managed_proxy_environment(char ***envp, const managed_proxy_t *mp)
{
const or_options_t *options = get_options();
@@ -867,7 +1052,10 @@ set_managed_proxy_environment(char ***envp, const managed_proxy_t *mp)
char *state_loc=NULL;
char *transports_to_launch=NULL;
char *bindaddr=NULL;
+ char *home_env=NULL;
+ char *path_env=NULL;
+ int r = -1;
int n_envs = mp->is_server ? ENVIRON_SIZE_SERVER : ENVIRON_SIZE_CLIENT;
/* allocate enough space for our env. vars and a NULL pointer */
@@ -878,8 +1066,13 @@ set_managed_proxy_environment(char ***envp, const managed_proxy_t *mp)
transports_to_launch =
smartlist_join_strings(mp->transports_to_launch, ",", 0, NULL);
- tor_asprintf(tmp++, "HOME=%s", getenv("HOME"));
- tor_asprintf(tmp++, "PATH=%s", getenv("PATH"));
+ home_env = getenv("HOME");
+ path_env = getenv("PATH");
+ if (!home_env || !path_env)
+ goto done;
+
+ tor_asprintf(tmp++, "HOME=%s", home_env);
+ tor_asprintf(tmp++, "PATH=%s", path_env);
tor_asprintf(tmp++, "TOR_PT_STATE_LOCATION=%s", state_loc);
tor_asprintf(tmp++, "TOR_PT_MANAGED_TRANSPORT_VER=1"); /* temp */
if (mp->is_server) {
@@ -896,11 +1089,18 @@ set_managed_proxy_environment(char ***envp, const managed_proxy_t *mp)
}
*tmp = NULL;
+ r = 0;
+
+ done:
tor_free(state_loc);
tor_free(transports_to_launch);
tor_free(bindaddr);
+
+ return r;
}
+#endif /* MS_WINDOWS */
+
/** Create and return a new managed proxy for <b>transport</b> using
* <b>proxy_argv</b>. If <b>is_server</b> is true, it's a server
* managed proxy. */
@@ -995,9 +1195,9 @@ pt_prepare_proxy_list_for_config_read(void)
SMARTLIST_FOREACH_BEGIN(managed_proxy_list, managed_proxy_t *, mp) {
/* Destroy unconfigured proxies. */
if (mp->conf_state != PT_PROTO_COMPLETED) {
- managed_proxy_destroy(mp);
- unconfigured_proxies_n--;
- continue;
+ managed_proxy_destroy(mp, 1);
+ unconfigured_proxies_n--;
+ continue;
}
tor_assert(mp->conf_state == PT_PROTO_COMPLETED);
@@ -1024,7 +1224,7 @@ sweep_proxy_list(void)
SMARTLIST_FOREACH_BEGIN(managed_proxy_list, managed_proxy_t *, mp) {
if (mp->marked_for_removal) {
SMARTLIST_DEL_CURRENT(managed_proxy_list, mp);
- managed_proxy_destroy(mp);
+ managed_proxy_destroy(mp, 1);
}
} SMARTLIST_FOREACH_END(mp);
}
@@ -1039,7 +1239,7 @@ pt_free_all(void)
free them. Otherwise, it hasn't registered its transports yet
and we should free them here. */
SMARTLIST_FOREACH(managed_proxy_list, managed_proxy_t *, mp,
- managed_proxy_destroy(mp));
+ managed_proxy_destroy(mp, 1));
smartlist_free(managed_proxy_list);
managed_proxy_list=NULL;
diff --git a/src/or/transports.h b/src/or/transports.h
index 4a93387596..314af2b3a0 100644
--- a/src/or/transports.h
+++ b/src/or/transports.h
@@ -36,7 +36,8 @@ enum pt_proto_state {
PT_PROTO_ACCEPTING_METHODS, /* accepting methods */
PT_PROTO_CONFIGURED, /* configured successfully */
PT_PROTO_COMPLETED, /* configure and registered its transports */
- PT_PROTO_BROKEN
+ PT_PROTO_BROKEN, /* broke during the protocol */
+ PT_PROTO_FAILED_LAUNCH /* failed while launching */
};
/** Structure containing information of a managed proxy. */
@@ -47,8 +48,8 @@ typedef struct {
int is_server; /* is it a server proxy? */
- FILE *_stdout; /* a stream to its stdout
- (closed in managed_proxy_destroy()) */
+ /* A pointer to the process handle of this managed proxy. */
+ process_handle_t *process_handle;
int pid; /* The Process ID this managed proxy is using. */