diff options
Diffstat (limited to 'src/or')
-rw-r--r-- | src/or/circuitbuild.c | 5 | ||||
-rw-r--r-- | src/or/circuituse.c | 11 | ||||
-rw-r--r-- | src/or/command.c | 1 | ||||
-rw-r--r-- | src/or/config.c | 38 | ||||
-rw-r--r-- | src/or/connection.c | 3 | ||||
-rw-r--r-- | src/or/control.c | 140 | ||||
-rw-r--r-- | src/or/control.h | 4 | ||||
-rw-r--r-- | src/or/directory.c | 2 | ||||
-rw-r--r-- | src/or/dirvote.c | 3 | ||||
-rw-r--r-- | src/or/eventdns.c | 5 | ||||
-rw-r--r-- | src/or/main.c | 5 | ||||
-rw-r--r-- | src/or/or.h | 15 | ||||
-rw-r--r-- | src/or/rendclient.c | 11 |
13 files changed, 207 insertions, 36 deletions
diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index 08bfb98815..9509b5ad18 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -262,7 +262,7 @@ circuit_build_times_test_frequency(void) } /** - * Retrieve and bounds-check the cbtmintimeout consensus paramter. + * Retrieve and bounds-check the cbtmintimeout consensus parameter. * * Effect: This is the minimum allowed timeout value in milliseconds. * The minimum is to prevent rounding to 0 (we only check once @@ -3766,7 +3766,6 @@ void entry_guards_compute_status(or_options_t *options, time_t now) { int changed = 0; - int severity = LOG_DEBUG; digestmap_t *reasons; if (! entry_guards) @@ -3793,8 +3792,6 @@ entry_guards_compute_status(or_options_t *options, time_t now) if (remove_dead_entry_guards(now)) changed = 1; - severity = changed ? LOG_DEBUG : LOG_INFO; - if (changed) { SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, entry) { const char *reason = digestmap_get(reasons, entry->identity); diff --git a/src/or/circuituse.c b/src/or/circuituse.c index 7289aa5c11..97ac5600a2 100644 --- a/src/or/circuituse.c +++ b/src/or/circuituse.c @@ -288,7 +288,6 @@ circuit_expire_building(void) struct timeval general_cutoff, begindir_cutoff, fourhop_cutoff, cannibalize_cutoff, close_cutoff, extremely_old_cutoff; struct timeval now; - struct timeval introcirc_cutoff; cpath_build_state_t *build_state; tor_gettimeofday(&now); @@ -307,8 +306,6 @@ circuit_expire_building(void) SET_CUTOFF(close_cutoff, circ_times.close_ms); SET_CUTOFF(extremely_old_cutoff, circ_times.close_ms*2 + 1000); - introcirc_cutoff = begindir_cutoff; - while (next_circ) { struct timeval cutoff; victim = next_circ; @@ -325,8 +322,6 @@ circuit_expire_building(void) cutoff = fourhop_cutoff; else if (TO_ORIGIN_CIRCUIT(victim)->has_opened) cutoff = cannibalize_cutoff; - else if (victim->purpose == CIRCUIT_PURPOSE_C_INTRODUCING) - cutoff = introcirc_cutoff; else if (victim->purpose == CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT) cutoff = close_cutoff; else @@ -337,12 +332,6 @@ circuit_expire_building(void) #if 0 /* some debug logs, to help track bugs */ - if (victim->purpose == CIRCUIT_PURPOSE_C_INTRODUCING && - victim->timestamp_created <= introcirc_cutoff && - victim->timestamp_created > general_cutoff) - log_info(LD_REND|LD_CIRC, "Timing out introduction circuit which we " - "would not have done if it had been a general circuit."); - if (victim->purpose >= CIRCUIT_PURPOSE_C_INTRODUCING && victim->purpose <= CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED) { if (!victim->timestamp_dirty) diff --git a/src/or/command.c b/src/or/command.c index 00d9af33fa..e377f4fb67 100644 --- a/src/or/command.c +++ b/src/or/command.c @@ -645,6 +645,7 @@ command_process_netinfo_cell(cell_t *cell, or_connection_t *conn) /* XXX maybe act on my_apparent_addr, if the source is sufficiently * trustworthy. */ + (void)my_apparent_addr; if (connection_or_set_state_open(conn)<0) connection_mark_for_close(TO_CONN(conn)); diff --git a/src/or/config.c b/src/or/config.c index 36fb991e33..117925549e 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -38,6 +38,8 @@ #include <shlobj.h> #endif +#include "procmon.h" + /** Enumeration of types which option values can take */ typedef enum config_type_t { CONFIG_TYPE_STRING = 0, /**< An arbitrary string. */ @@ -398,6 +400,7 @@ static config_var_t _option_vars[] = { VAR("__LeaveStreamsUnattached",BOOL, LeaveStreamsUnattached, "0"), VAR("__HashedControlSessionPassword", LINELIST, HashedControlSessionPassword, NULL), + VAR("__OwningControllerProcess",STRING,OwningControllerProcess, NULL), V(MinUptimeHidServDirectoryV2, INTERVAL, "24 hours"), V(_UsingTestNetworkDefaults, BOOL, "0"), @@ -1169,12 +1172,26 @@ options_act(or_options_t *old_options) or_options_t *options = get_options(); int running_tor = options->command == CMD_RUN_TOR; char *msg; + const int transition_affects_workers = + old_options && options_transition_affects_workers(old_options, options); if (running_tor && !have_lockfile()) { if (try_locking(options, 1) < 0) return -1; } + /* We want to reinit keys as needed before we do much of anything else: + keys are important, and other things can depend on them. */ + if (running_tor && + (transition_affects_workers || + (options->V3AuthoritativeDir && (!old_options || + !old_options->V3AuthoritativeDir)))) { + if (init_keys() < 0) { + log_warn(LD_BUG,"Error initializing keys; exiting"); + return -1; + } + } + if (consider_adding_dir_authorities(options, old_options) < 0) return -1; @@ -1241,6 +1258,8 @@ options_act(or_options_t *old_options) return -1; } + monitor_owning_controller_process(options->OwningControllerProcess); + /* reload keys as needed for rendezvous services. */ if (rend_service_load_keys()<0) { log_warn(LD_GENERAL,"Error loading rendezvous service keys"); @@ -1341,14 +1360,10 @@ options_act(or_options_t *old_options) } } - if (options_transition_affects_workers(old_options, options)) { + if (transition_affects_workers) { log_info(LD_GENERAL, "Worker-related options changed. Rotating workers."); - if (init_keys() < 0) { - log_warn(LD_BUG,"Error initializing keys; exiting"); - return -1; - } if (server_mode(options) && !server_mode(old_options)) { ip_address_changed(0); if (can_complete_circuit || !any_predicted_circuits(time(NULL))) @@ -1362,9 +1377,6 @@ options_act(or_options_t *old_options) return -1; } - if (options->V3AuthoritativeDir && !old_options->V3AuthoritativeDir) - init_keys(); - if (options->PerConnBWRate != old_options->PerConnBWRate || options->PerConnBWBurst != old_options->PerConnBWBurst) connection_or_update_token_buckets(get_connection_array(), options); @@ -3480,6 +3492,16 @@ options_validate(or_options_t *old_options, or_options_t *options, } } + if (options->OwningControllerProcess) { + const char *validate_pspec_msg = NULL; + if (tor_validate_process_specifier(options->OwningControllerProcess, + &validate_pspec_msg)) { + tor_asprintf(msg, "Bad OwningControllerProcess: %s", + validate_pspec_msg); + return -1; + } + } + if (options->ControlListenAddress) { int all_are_local = 1; config_line_t *ln; diff --git a/src/or/connection.c b/src/or/connection.c index e58aba3d98..6644b4cd76 100644 --- a/src/or/connection.c +++ b/src/or/connection.c @@ -479,8 +479,7 @@ connection_free(connection_t *conn) } } if (conn->type == CONN_TYPE_CONTROL) { - TO_CONTROL_CONN(conn)->event_mask = 0; - control_update_global_event_mask(); + connection_control_closed(TO_CONTROL_CONN(conn)); } connection_unregister_events(conn); _connection_free(conn); diff --git a/src/or/control.c b/src/or/control.c index a595b2a638..c7e22f81e2 100644 --- a/src/or/control.c +++ b/src/or/control.c @@ -32,6 +32,8 @@ #include "routerlist.h" #include "routerparse.h" +#include "procmon.h" + /** Yield true iff <b>s</b> is the state of a control_connection_t that has * finished authentication and is accepting commands. */ #define STATE_IS_OPEN(s) ((s) == CONTROL_CONN_STATE_OPEN) @@ -1275,6 +1277,26 @@ handle_control_signal(control_connection_t *conn, uint32_t len, return 0; } +/** Called when we get a TAKEOWNERSHIP command. Mark this connection + * as an owning connection, so that we will exit if the connection + * closes. */ +static int +handle_control_takeownership(control_connection_t *conn, uint32_t len, + const char *body) +{ + (void)len; + (void)body; + + conn->is_owning_control_connection = 1; + + log_info(LD_CONTROL, "Control connection %d has taken ownership of this " + "Tor instance.", + (int)(conn->_base.s)); + + send_control_done(conn); + return 0; +} + /** Called when we get a MAPADDRESS command; try to bind all listed addresses, * and report success or failure. */ static int @@ -2010,8 +2032,8 @@ static const getinfo_item_t getinfo_items[] = { "v2 networkstatus docs as retrieved from a DirPort."), ITEM("dir/status-vote/current/consensus", dir, "v3 Networkstatus consensus as retrieved from a DirPort."), - PREFIX("exit-policy/default", policies, - "The default value appended to the configured exit policy."), + ITEM("exit-policy/default", policies, + "The default value appended to the configured exit policy."), PREFIX("ip-to-country/", geoip, "Perform a GEOIP lookup"), { NULL, NULL, NULL, 0 } }; @@ -2842,6 +2864,43 @@ connection_control_reached_eof(control_connection_t *conn) return 0; } +/** Shut down this Tor instance in the same way that SIGINT would, but + * with a log message appropriate for the loss of an owning controller. */ +static void +lost_owning_controller(const char *owner_type, const char *loss_manner) +{ + int shutdown_slowly = server_mode(get_options()); + + log_notice(LD_CONTROL, "Owning controller %s has %s -- %s.", + owner_type, loss_manner, + shutdown_slowly ? "shutting down" : "exiting now"); + + /* XXXX Perhaps this chunk of code should be a separate function, + * called here and by process_signal(SIGINT). */ + + if (!shutdown_slowly) { + tor_cleanup(); + exit(0); + } + /* XXXX This will close all listening sockets except control-port + * listeners. Perhaps we should close those too. */ + hibernate_begin_shutdown(); +} + +/** Called when <b>conn</b> is being freed. */ +void +connection_control_closed(control_connection_t *conn) +{ + tor_assert(conn); + + conn->event_mask = 0; + control_update_global_event_mask(); + + if (conn->is_owning_control_connection) { + lost_owning_controller("connection", "closed"); + } +} + /** Return true iff <b>cmd</b> is allowable (or at least forgivable) at this * stage of the protocol. */ static int @@ -2997,6 +3056,9 @@ connection_control_process_inbuf(control_connection_t *conn) return 0; } + /* XXXX Why is this not implemented as a table like the GETINFO + * items are? Even handling the plus signs at the beginnings of + * commands wouldn't be very hard with proper macros. */ cmd_data_len = (uint32_t)data_len; if (!strcasecmp(conn->incoming_cmd, "SETCONF")) { if (handle_control_setconf(conn, cmd_data_len, args)) @@ -3022,6 +3084,9 @@ connection_control_process_inbuf(control_connection_t *conn) } else if (!strcasecmp(conn->incoming_cmd, "SIGNAL")) { if (handle_control_signal(conn, cmd_data_len, args)) return -1; + } else if (!strcasecmp(conn->incoming_cmd, "TAKEOWNERSHIP")) { + if (handle_control_takeownership(conn, cmd_data_len, args)) + return -1; } else if (!strcasecmp(conn->incoming_cmd, "MAPADDRESS")) { if (handle_control_mapaddress(conn, cmd_data_len, args)) return -1; @@ -3077,7 +3142,6 @@ control_event_circuit_status(origin_circuit_t *circ, circuit_status_event_t tp, { const char *status; char extended_buf[96]; - int providing_reason=0; if (!EVENT_IS_INTERESTING(EVENT_CIRCUIT_STATUS)) return 0; tor_assert(circ); @@ -3101,7 +3165,6 @@ control_event_circuit_status(origin_circuit_t *circ, circuit_status_event_t tp, const char *reason_str = circuit_end_reason_to_control_string(reason_code); char *reason = NULL; size_t n=strlen(extended_buf); - providing_reason=1; if (!reason_str) { reason = tor_malloc(16); tor_snprintf(reason, 16, "UNKNOWN_%d", reason_code); @@ -3884,6 +3947,75 @@ init_cookie_authentication(int enabled) return 0; } +/** A copy of the process specifier of Tor's owning controller, or + * NULL if this Tor instance is not currently owned by a process. */ +static char *owning_controller_process_spec = NULL; + +/** A process-termination monitor for Tor's owning controller, or NULL + * if this Tor instance is not currently owned by a process. */ +static tor_process_monitor_t *owning_controller_process_monitor = NULL; + +/** Process-termination monitor callback for Tor's owning controller + * process. */ +static void +owning_controller_procmon_cb(void *unused) +{ + (void)unused; + + lost_owning_controller("process", "vanished"); +} + +/** Set <b>process_spec</b> as Tor's owning controller process. + * Exit on failure. */ +void +monitor_owning_controller_process(const char *process_spec) +{ + const char *msg; + + tor_assert((owning_controller_process_spec == NULL) == + (owning_controller_process_monitor == NULL)); + + if (owning_controller_process_spec != NULL) { + if ((process_spec != NULL) && !strcmp(process_spec, + owning_controller_process_spec)) { + /* Same process -- return now, instead of disposing of and + * recreating the process-termination monitor. */ + return; + } + + /* We are currently owned by a process, and we should no longer be + * owned by it. Free the process-termination monitor. */ + tor_process_monitor_free(owning_controller_process_monitor); + owning_controller_process_monitor = NULL; + + tor_free(owning_controller_process_spec); + owning_controller_process_spec = NULL; + } + + tor_assert((owning_controller_process_spec == NULL) && + (owning_controller_process_monitor == NULL)); + + if (process_spec == NULL) + return; + + owning_controller_process_spec = tor_strdup(process_spec); + owning_controller_process_monitor = + tor_process_monitor_new(tor_libevent_get_base(), + owning_controller_process_spec, + LD_CONTROL, + owning_controller_procmon_cb, NULL, + &msg); + + if (owning_controller_process_monitor == NULL) { + log_err(LD_BUG, "Couldn't create process-termination monitor for " + "owning controller: %s. Exiting.", + msg); + owning_controller_process_spec = NULL; + tor_cleanup(); + exit(0); + } +} + /** Convert the name of a bootstrapping phase <b>s</b> into strings * <b>tag</b> and <b>summary</b> suitable for display by the controller. */ static int diff --git a/src/or/control.h b/src/or/control.h index a73ed5d3c1..ddea4cd548 100644 --- a/src/or/control.h +++ b/src/or/control.h @@ -27,6 +27,8 @@ void control_ports_write_to_file(void); int connection_control_finished_flushing(control_connection_t *conn); int connection_control_reached_eof(control_connection_t *conn); +void connection_control_closed(control_connection_t *conn); + int connection_control_process_inbuf(control_connection_t *conn); #define EVENT_AUTHDIR_NEWDESCS 0x000D @@ -72,6 +74,8 @@ smartlist_t *decode_hashed_passwords(config_line_t *passwords); void disable_control_logging(void); void enable_control_logging(void); +void monitor_owning_controller_process(const char *process_spec); + void control_event_bootstrap(bootstrap_status_t status, int progress); void control_event_bootstrap_problem(const char *warn, int reason); diff --git a/src/or/directory.c b/src/or/directory.c index eb99e9d081..ff0a5a427b 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -1900,7 +1900,6 @@ connection_dir_client_reached_eof(dir_connection_t *conn) router_get_trusteddirserver_by_digest(conn->identity_digest); char *rejected_hdr = http_get_header(headers, "X-Descriptor-Not-New: "); - int rejected = 0; if (rejected_hdr) { if (!strcmp(rejected_hdr, "Yes")) { log_info(LD_GENERAL, @@ -1913,7 +1912,6 @@ connection_dir_client_reached_eof(dir_connection_t *conn) * last descriptor, not on the published time of the last * descriptor. If those are different, that's a bad thing to * do. -NM */ - rejected = 1; } tor_free(rejected_hdr); } diff --git a/src/or/dirvote.c b/src/or/dirvote.c index 96e3df5cec..c6ce9f6776 100644 --- a/src/or/dirvote.c +++ b/src/or/dirvote.c @@ -1592,7 +1592,7 @@ networkstatus_compute_consensus(smartlist_t *votes, * is the same flag as votes[j]->known_flags[b]. */ int *named_flag; /* Index of the flag "Named" for votes[j] */ int *unnamed_flag; /* Index of the flag "Unnamed" for votes[j] */ - int chosen_named_idx, chosen_unnamed_idx; + int chosen_named_idx; strmap_t *name_to_id_map = strmap_new(); char conflict[DIGEST_LEN]; @@ -1610,7 +1610,6 @@ networkstatus_compute_consensus(smartlist_t *votes, for (i = 0; i < smartlist_len(votes); ++i) unnamed_flag[i] = named_flag[i] = -1; chosen_named_idx = smartlist_string_pos(flags, "Named"); - chosen_unnamed_idx = smartlist_string_pos(flags, "Unnamed"); /* Build the flag index. */ SMARTLIST_FOREACH(votes, networkstatus_t *, v, diff --git a/src/or/eventdns.c b/src/or/eventdns.c index d06fb2cf21..42e16aec7a 100644 --- a/src/or/eventdns.c +++ b/src/or/eventdns.c @@ -1028,6 +1028,9 @@ request_parse(u8 *packet, ssize_t length, struct evdns_server_port *port, struct GET16(answers); GET16(authority); GET16(additional); + (void)additional; + (void)authority; + (void)answers; if (flags & 0x8000) return -1; /* Must not be an answer. */ flags &= 0x0110; /* Only RD and CD get preserved. */ @@ -2288,7 +2291,7 @@ _evdns_nameserver_add_impl(const struct sockaddr *address, evtimer_set(&ns->timeout_event, nameserver_prod_callback, ns); - ns->socket = socket(PF_INET, SOCK_DGRAM, 0); + ns->socket = socket(address->sa_family, SOCK_DGRAM, 0); if (ns->socket < 0) { err = 1; goto out1; } #ifdef WIN32 { diff --git a/src/or/main.c b/src/or/main.c index a8146e7993..adbde9044f 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -1164,7 +1164,10 @@ run_scheduled_events(time_t now) * it's not comfortable with the number of available circuits. */ /* XXXX022 If our circuit build timeout is much lower than a second, maybe - we should do this more often? */ + * we should do this more often? -NM + * It can't be lower than 1.5 seconds currently; see + * circuit_build_times_min_timeout(). -RD + */ circuit_expire_building(); /** 3b. Also look at pending streams and prune the ones that 'began' diff --git a/src/or/or.h b/src/or/or.h index ae56dcd9b4..97fecd1500 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -1009,7 +1009,7 @@ typedef struct connection_t { /* XXXX023 move this field, and all the listener-only fields (just socket_family, I think), into a new listener_connection_t subtype. */ /** If the connection is a CONN_TYPE_AP_DNS_LISTENER, this field points - * to the evdns_server_port is uses to listen to and answer connections. */ + * to the evdns_server_port it uses to listen to and answer connections. */ struct evdns_server_port *dns_server_port; /** Unique ID for measuring tunneled network status requests. */ @@ -1242,6 +1242,9 @@ typedef struct control_connection_t { /** True if we have sent a protocolinfo reply on this connection. */ unsigned int have_sent_protocolinfo:1; + /** True if we have received a takeownership command on this + * connection. */ + unsigned int is_owning_control_connection:1; /** Amount of space allocated in incoming_cmd. */ uint32_t incoming_cmd_len; @@ -2140,6 +2143,11 @@ typedef struct circuit_t { * in time in order to indicate that a circuit shouldn't be used for new * streams, but that it can stay alive as long as it has streams on it. * That's a kludge we should fix. + * + * XXX023 The CBT code uses this field to record when HS-related + * circuits entered certain states. This usage probably won't + * interfere with this field's primary purpose, but we should + * document it more thoroughly to make sure of that. */ time_t timestamp_dirty; @@ -2674,6 +2682,11 @@ typedef struct { int DisablePredictedCircuits; /**< Boolean: does Tor preemptively * make circuits in the background (0), * or not (1)? */ + + /** Process specifier for a controller that ‘owns’ this Tor + * instance. Tor will terminate if its owning controller does. */ + char *OwningControllerProcess; + int ShutdownWaitLength; /**< When we get a SIGINT and we're a server, how * long do we wait before exiting? */ char *SafeLogging; /**< Contains "relay", "1", "0" (meaning no scrubbing). */ diff --git a/src/or/rendclient.c b/src/or/rendclient.c index 77e11c2a07..a5423394f7 100644 --- a/src/or/rendclient.c +++ b/src/or/rendclient.c @@ -275,6 +275,10 @@ rend_client_send_introduction(origin_circuit_t *introcirc, /* Now, we wait for an ACK or NAK on this circuit. */ introcirc->_base.purpose = CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT; + /* Set timestamp_dirty, because circuit_expire_building expects it + * to specify when a circuit entered the _C_INTRODUCE_ACK_WAIT + * state. */ + introcirc->_base.timestamp_dirty = time(NULL); return 0; perm_err: @@ -329,6 +333,10 @@ rend_client_introduction_acked(origin_circuit_t *circ, circ->rend_data->onion_address, CIRCUIT_PURPOSE_C_REND_READY); if (rendcirc) { /* remember the ack */ rendcirc->_base.purpose = CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED; + /* Set timestamp_dirty, because circuit_expire_building expects + * it to specify when a circuit entered the + * _C_REND_READY_INTRO_ACKED state. */ + rendcirc->_base.timestamp_dirty = time(NULL); } else { log_info(LD_REND,"...Found no rend circ. Dropping on the floor."); } @@ -674,6 +682,9 @@ rend_client_rendezvous_acked(origin_circuit_t *circ, const uint8_t *request, log_info(LD_REND,"Got rendezvous ack. This circuit is now ready for " "rendezvous."); circ->_base.purpose = CIRCUIT_PURPOSE_C_REND_READY; + /* Set timestamp_dirty, because circuit_expire_building expects it + * to specify when a circuit entered the _C_REND_READY state. */ + circ->_base.timestamp_dirty = time(NULL); /* XXXX023 This is a pretty brute-force approach. It'd be better to * attach only the connections that are waiting on this circuit, rather * than trying to attach them all. See comments bug 743. */ |