mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-28 06:13:31 +01:00
New 'DisableNetwork' option to prevent Tor from using the network
Some controllers want this so they can mess with Tor's configuration for a while via the control port before actually letting Tor out of the house. We do this with a new DisableNetwork option, that prevents Tor from making any outbound connections or binding any non-control listeners. Additionally, it shuts down the same functionality as shuts down when we are hibernating, plus the code that launches directory downloads. To make sure I didn't miss anything, I added a clause straight to connection_connect, so that we won't even try to open an outbound socket when the network is disabled. In my testing, I made this an assert, but since I probably missed something, I've turned it into a BUG warning for testing.
This commit is contained in:
parent
b5a306e82c
commit
df9b76460c
9
changes/disable_network
Normal file
9
changes/disable_network
Normal file
@ -0,0 +1,9 @@
|
||||
o Minor features:
|
||||
|
||||
- New "DisableNetwork" option to prevent Tor from launching any
|
||||
connections or accepting any connections except on a control
|
||||
port. Some bundles and controllers want to use this so they can
|
||||
configure Tor before letting Tor talk to the rest of the
|
||||
network--for example, to prevent any connections from being made
|
||||
to a non-bridge address.
|
||||
|
@ -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),
|
||||
@ -1093,13 +1094,19 @@ 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 */
|
||||
connection_mark_all_noncontrol_connections();
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(HAVE_NET_IF_H) && defined(HAVE_NET_PFVAR_H)
|
||||
@ -4094,6 +4101,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) ||
|
||||
|
@ -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 (!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;
|
||||
}
|
||||
|
||||
/** DOCDOC */
|
||||
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);
|
||||
}
|
||||
|
||||
/** DOCDOC */
|
||||
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
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -934,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);
|
||||
}
|
||||
@ -1161,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())
|
||||
@ -1219,7 +1219,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);
|
||||
@ -1355,7 +1355,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);
|
||||
@ -1430,7 +1430,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;
|
||||
}
|
||||
@ -1441,7 +1441,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 */
|
||||
@ -1472,7 +1472,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();
|
||||
}
|
||||
@ -1489,7 +1489,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 {
|
||||
@ -1508,7 +1509,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
|
||||
@ -1520,7 +1522,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 */
|
||||
@ -1592,7 +1594,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 !=
|
||||
@ -1793,6 +1795,7 @@ do_hup(void)
|
||||
/* retry appropriate downloads */
|
||||
router_reset_status_download_failures();
|
||||
router_reset_descriptor_download_failures();
|
||||
if (!options->DisableNetwork)
|
||||
update_networkstatus_downloads(time(NULL));
|
||||
|
||||
/* We'll retry routerstatus downloads in about 10 seconds; no need to
|
||||
|
@ -3439,6 +3439,10 @@ typedef struct {
|
||||
* 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. */
|
||||
|
@ -780,7 +780,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;
|
||||
}
|
||||
|
||||
@ -806,7 +806,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;
|
||||
@ -974,6 +974,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.
|
||||
*/
|
||||
|
@ -39,6 +39,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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user