diff options
Diffstat (limited to 'src/core/mainloop/connection.c')
-rw-r--r-- | src/core/mainloop/connection.c | 103 |
1 files changed, 51 insertions, 52 deletions
diff --git a/src/core/mainloop/connection.c b/src/core/mainloop/connection.c index c827af7a9a..b17d7bf2bd 100644 --- a/src/core/mainloop/connection.c +++ b/src/core/mainloop/connection.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -106,7 +106,6 @@ #include "feature/relay/dns.h" #include "feature/relay/ext_orport.h" #include "feature/relay/routermode.h" -#include "feature/rend/rendclient.h" #include "feature/rend/rendcommon.h" #include "feature/stats/connstats.h" #include "feature/stats/rephist.h" @@ -898,7 +897,6 @@ connection_free_minimal(connection_t *conn) } } if (CONN_IS_EDGE(conn)) { - rend_data_free(TO_EDGE_CONN(conn)->rend_data); hs_ident_edge_conn_free(TO_EDGE_CONN(conn)->hs_ident); } if (conn->type == CONN_TYPE_CONTROL) { @@ -927,7 +925,6 @@ connection_free_minimal(connection_t *conn) tor_compress_free(dir_conn->compress_state); dir_conn_clear_spool(dir_conn); - rend_data_free(dir_conn->rend_data); hs_ident_dir_conn_free(dir_conn->hs_ident); if (dir_conn->guard_state) { /* Cancel before freeing, if it's still there. */ @@ -948,7 +945,6 @@ connection_free_minimal(connection_t *conn) connection_or_clear_identity(TO_OR_CONN(conn)); } if (conn->type == CONN_TYPE_OR || conn->type == CONN_TYPE_EXT_OR) { - connection_or_remove_from_ext_or_id_map(TO_OR_CONN(conn)); tor_free(TO_OR_CONN(conn)->ext_or_conn_id); tor_free(TO_OR_CONN(conn)->ext_or_auth_correct_client_hash); tor_free(TO_OR_CONN(conn)->ext_or_transport); @@ -1243,12 +1239,34 @@ create_unix_sockaddr(const char *listenaddress, char **readable_address, } #endif /* defined(HAVE_SYS_UN_H) || defined(RUNNING_DOXYGEN) */ -/** Warn that an accept or a connect has failed because we're running out of - * TCP sockets we can use on current system. Rate-limit these warnings so - * that we don't spam the log. */ +/** + * A socket failed from resource exhaustion. + * + * Among other actions, warn that an accept or a connect has failed because + * we're running out of TCP sockets we can use on current system. Rate-limit + * these warnings so that we don't spam the log. */ static void -warn_too_many_conns(void) +socket_failed_from_resource_exhaustion(void) { + /* When we get to this point we know that a socket could not be + * established. However the kernel does not let us know whether the reason is + * because we ran out of TCP source ports, or because we exhausted all the + * FDs on this system, or for any other reason. + * + * For this reason, we are going to use the following heuristic: If our + * system supports a lot of sockets, we will assume that it's a problem of + * TCP port exhaustion. Otherwise, if our system does not support many + * sockets, we will assume that this is because of file descriptor + * exhaustion. + */ + if (get_max_sockets() > 65535) { + /* TCP port exhaustion */ + rep_hist_note_overload(OVERLOAD_GENERAL); + } else { + /* File descriptor exhaustion */ + rep_hist_note_overload(OVERLOAD_FD_EXHAUSTED); + } + #define WARN_TOO_MANY_CONNS_INTERVAL (6*60*60) static ratelim_t last_warned = RATELIM_INIT(WARN_TOO_MANY_CONNS_INTERVAL); char *m; @@ -1477,7 +1495,7 @@ connection_listener_new(const struct sockaddr *listensockaddr, if (!SOCKET_OK(s)) { int e = tor_socket_errno(s); if (ERRNO_IS_RESOURCE_LIMIT(e)) { - warn_too_many_conns(); + socket_failed_from_resource_exhaustion(); /* * We'll call the OOS handler at the error exit, so set the * exhaustion flag for it. @@ -1603,7 +1621,7 @@ connection_listener_new(const struct sockaddr *listensockaddr, if (! SOCKET_OK(s)) { int e = tor_socket_errno(s); if (ERRNO_IS_RESOURCE_LIMIT(e)) { - warn_too_many_conns(); + socket_failed_from_resource_exhaustion(); /* * We'll call the OOS handler at the error exit, so set the * exhaustion flag for it. @@ -1718,13 +1736,6 @@ connection_listener_new(const struct sockaddr *listensockaddr, } } - /* Force IPv4 and IPv6 traffic on for non-SOCKSPorts. - * Forcing options on isn't a good idea, see #32994 and #33607. */ - if (type != CONN_TYPE_AP_LISTENER) { - lis_conn->entry_cfg.ipv4_traffic = 1; - lis_conn->entry_cfg.ipv6_traffic = 1; - } - if (connection_add(conn) < 0) { /* no space, forget it */ log_warn(LD_NET,"connection_add for listener failed. Giving up."); goto err; @@ -1923,7 +1934,7 @@ connection_handle_listener_read(connection_t *conn, int new_type) connection_check_oos(get_n_open_sockets(), 0); return 0; } else if (ERRNO_IS_RESOURCE_LIMIT(e)) { - warn_too_many_conns(); + socket_failed_from_resource_exhaustion(); /* Exhaustion; tell the OOS handler */ connection_check_oos(get_n_open_sockets(), 1); return 0; @@ -2186,7 +2197,7 @@ connection_connect_sockaddr,(connection_t *conn, */ *socket_error = tor_socket_errno(s); if (ERRNO_IS_RESOURCE_LIMIT(*socket_error)) { - warn_too_many_conns(); + socket_failed_from_resource_exhaustion(); connection_check_oos(get_n_open_sockets(), 1); } else { log_warn(LD_NET,"Error creating network socket: %s", @@ -3246,7 +3257,7 @@ retry_all_listeners(smartlist_t *new_conns, int close_all_noncontrol) * we hit those, bail early so tor can stop. */ if (!new_conn) { log_warn(LD_NET, "Unable to create listener port: %s:%d", - fmt_addr(&r->new_port->addr), r->new_port->port); + fmt_and_decorate_addr(&r->new_port->addr), r->new_port->port); retval = -1; break; } @@ -3265,7 +3276,8 @@ retry_all_listeners(smartlist_t *new_conns, int close_all_noncontrol) * any configured port. Kill 'em. */ SMARTLIST_FOREACH_BEGIN(listeners, connection_t *, conn) { log_notice(LD_NET, "Closing no-longer-configured %s on %s:%d", - conn_type_to_string(conn->type), conn->address, conn->port); + conn_type_to_string(conn->type), + fmt_and_decorate_addr(&conn->addr), conn->port); connection_close_immediate(conn); connection_mark_for_close(conn); } SMARTLIST_FOREACH_END(conn); @@ -3427,6 +3439,16 @@ connection_bucket_read_limit(connection_t *conn, time_t now) int priority = conn->type != CONN_TYPE_DIR; ssize_t conn_bucket = -1; size_t global_bucket_val = token_bucket_rw_get_read(&global_bucket); + if (global_bucket_val == 0) { + /* We reached our global read limit: count this as an overload. + * + * The token bucket is always initialized (see connection_bucket_init() and + * options_validate_relay_bandwidth()) and hence we can assume that if the + * token ever hits zero, it's a limit that got popped and not the bucket + * being uninitialized. + */ + rep_hist_note_overload(OVERLOAD_READ); + } if (connection_speaks_cells(conn)) { or_connection_t *or_conn = TO_OR_CONN(conn); @@ -3457,6 +3479,11 @@ connection_bucket_write_limit(connection_t *conn, time_t now) int priority = conn->type != CONN_TYPE_DIR; size_t conn_bucket = buf_datalen(conn->outbuf); size_t global_bucket_val = token_bucket_rw_get_write(&global_bucket); + if (global_bucket_val == 0) { + /* We reached our global write limit: We should count this as an overload. + * See above function for more information */ + rep_hist_note_overload(OVERLOAD_WRITE); + } if (!connection_is_rate_limited(conn)) { /* be willing to write to local conns even if our buckets are empty */ @@ -4812,34 +4839,6 @@ connection_get_by_type_nonlinked,(int type)) CONN_GET_TEMPLATE(conn, conn->type == type && !conn->linked); } -/** Return a connection of type <b>type</b> that has rendquery equal - * to <b>rendquery</b>, and that is not marked for close. If state - * is non-zero, conn must be of that state too. - */ -connection_t * -connection_get_by_type_state_rendquery(int type, int state, - const char *rendquery) -{ - tor_assert(type == CONN_TYPE_DIR || - type == CONN_TYPE_AP || type == CONN_TYPE_EXIT); - tor_assert(rendquery); - - CONN_GET_TEMPLATE(conn, - (conn->type == type && - (!state || state == conn->state)) && - ( - (type == CONN_TYPE_DIR && - TO_DIR_CONN(conn)->rend_data && - !rend_cmp_service_ids(rendquery, - rend_data_get_address(TO_DIR_CONN(conn)->rend_data))) - || - (CONN_IS_EDGE(conn) && - TO_EDGE_CONN(conn)->rend_data && - !rend_cmp_service_ids(rendquery, - rend_data_get_address(TO_EDGE_CONN(conn)->rend_data))) - )); -} - /** Return a new smartlist of dir_connection_t * from get_connection_array() * that satisfy conn_test on connection_t *conn_var, and dirconn_test on * dir_connection_t *dirconn_var. conn_var must be of CONN_TYPE_DIR and not @@ -5829,7 +5828,6 @@ connection_free_all(void) /* Unlink everything from the identity map. */ connection_or_clear_identity_map(); - connection_or_clear_ext_or_id_map(); /* Clear out our list of broken connections */ clear_broken_connection_map(0); @@ -5866,7 +5864,8 @@ clock_skew_warning, (const connection_t *conn, long apparent_skew, int trusted, char *ext_source = NULL, *warn = NULL; format_time_interval(dbuf, sizeof(dbuf), apparent_skew); if (conn) - tor_asprintf(&ext_source, "%s:%s:%d", source, conn->address, conn->port); + tor_asprintf(&ext_source, "%s:%s:%d", source, + fmt_and_decorate_addr(&conn->addr), conn->port); else ext_source = tor_strdup(source); log_fn(trusted ? LOG_WARN : LOG_INFO, domain, |