summaryrefslogtreecommitdiff
path: root/src/or/connection.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/or/connection.c')
-rw-r--r--src/or/connection.c297
1 files changed, 210 insertions, 87 deletions
diff --git a/src/or/connection.c b/src/or/connection.c
index 78176d3768..c0031047e7 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -678,6 +678,13 @@ connection_free,(connection_t *conn))
if (conn->type == CONN_TYPE_CONTROL) {
connection_control_closed(TO_CONTROL_CONN(conn));
}
+#if 1
+ /* DEBUGGING */
+ if (conn->type == CONN_TYPE_AP) {
+ connection_ap_warn_and_unmark_if_pending_circ(TO_ENTRY_CONN(conn),
+ "connection_free");
+ }
+#endif
connection_unregister_events(conn);
connection_free_(conn);
}
@@ -1128,11 +1135,12 @@ connection_listener_new(const struct sockaddr *listensockaddr,
tor_socket_strerror(errno));
}
-#if defined USE_TRANSPARENT && defined(IP_TRANSPARENT)
+#if defined(USE_TRANSPARENT) && defined(IP_TRANSPARENT)
if (options->TransProxyType_parsed == TPT_TPROXY &&
type == CONN_TYPE_AP_TRANS_LISTENER) {
int one = 1;
- if (setsockopt(s, SOL_IP, IP_TRANSPARENT, &one, sizeof(one)) < 0) {
+ if (setsockopt(s, SOL_IP, IP_TRANSPARENT, (void*)&one,
+ (socklen_t)sizeof(one)) < 0) {
const char *extra = "";
int e = tor_socket_errno(s);
if (e == EPERM)
@@ -1146,16 +1154,11 @@ connection_listener_new(const struct sockaddr *listensockaddr,
#ifdef IPV6_V6ONLY
if (listensockaddr->sa_family == AF_INET6) {
-#ifdef _WIN32
- /* In Redmond, this kind of thing passes for standards-conformance. */
- DWORD one = 1;
-#else
int one = 1;
-#endif
/* We need to set IPV6_V6ONLY so that this socket can't get used for
* IPv4 connections. */
if (setsockopt(s,IPPROTO_IPV6, IPV6_V6ONLY,
- (void*)&one, sizeof(one)) < 0) {
+ (void*)&one, (socklen_t)sizeof(one)) < 0) {
int e = tor_socket_errno(s);
log_warn(LD_NET, "Error setting IPV6_V6ONLY flag: %s",
tor_socket_strerror(e));
@@ -1597,6 +1600,8 @@ connection_init_accepted_conn(connection_t *conn,
break;
case CONN_TYPE_AP_TRANS_LISTENER:
TO_ENTRY_CONN(conn)->is_transparent_ap = 1;
+ /* XXXX028 -- is this correct still, with the addition of
+ * pending_entry_connections ? */
conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
return connection_ap_process_transparent(TO_ENTRY_CONN(conn));
case CONN_TYPE_AP_NATD_LISTENER:
@@ -1616,13 +1621,18 @@ connection_init_accepted_conn(connection_t *conn,
return 0;
}
-static int
-connection_connect_sockaddr(connection_t *conn,
+/** Take conn, make a nonblocking socket; try to connect to
+ * sa, binding to bindaddr if sa is not localhost. If fail, return -1 and if
+ * applicable put your best guess about errno into *<b>socket_error</b>.
+ * If connected return 1, if EAGAIN return 0.
+ */
+MOCK_IMPL(STATIC int,
+connection_connect_sockaddr,(connection_t *conn,
const struct sockaddr *sa,
socklen_t sa_len,
const struct sockaddr *bindaddr,
socklen_t bindaddr_len,
- int *socket_error)
+ int *socket_error))
{
tor_socket_t s;
int inprogress = 0;
@@ -1706,10 +1716,13 @@ connection_connect_sockaddr(connection_t *conn,
}
/** Take conn, make a nonblocking socket; try to connect to
- * addr:port (they arrive in *host order*). If fail, return -1 and if
+ * addr:port (port arrives in *host order*). If fail, return -1 and if
* applicable put your best guess about errno into *<b>socket_error</b>.
* Else assign s to conn-\>s: if connected return 1, if EAGAIN return 0.
*
+ * addr:port can be different to conn->addr:conn->port if connecting through
+ * a proxy.
+ *
* address is used to make the logs useful.
*
* On success, add conn to the list of polled connections.
@@ -2381,6 +2394,14 @@ retry_listener_ports(smartlist_t *old_conns,
if (port->server_cfg.no_listen)
continue;
+#ifndef _WIN32
+ /* We don't need to be root to create a UNIX socket, so defer until after
+ * setuid. */
+ const or_options_t *options = get_options();
+ if (port->is_unix_addr && !geteuid() && strcmp(options->User, "root"))
+ continue;
+#endif
+
if (port->is_unix_addr) {
listensockaddr = (struct sockaddr *)
create_unix_sockaddr(port->unix_addr,
@@ -4209,24 +4230,32 @@ connection_write_to_buf_impl_,(const char *string, size_t len,
}
}
+/** Return a connection_t * from get_connection_array() that satisfies test on
+ * var, and that is not marked for close. */
+#define CONN_GET_TEMPLATE(var, test) \
+ STMT_BEGIN \
+ smartlist_t *conns = get_connection_array(); \
+ SMARTLIST_FOREACH(conns, connection_t *, var, \
+ { \
+ if (var && (test) && !var->marked_for_close) \
+ return var; \
+ }); \
+ return NULL; \
+ STMT_END
+
/** Return a connection with given type, address, port, and purpose;
- * or NULL if no such connection exists. */
+ * or NULL if no such connection exists (or if all such connections are marked
+ * for close). */
connection_t *
connection_get_by_type_addr_port_purpose(int type,
const tor_addr_t *addr, uint16_t port,
int purpose)
{
- smartlist_t *conns = get_connection_array();
- SMARTLIST_FOREACH(conns, connection_t *, conn,
- {
- if (conn->type == type &&
+ CONN_GET_TEMPLATE(conn,
+ (conn->type == type &&
tor_addr_eq(&conn->addr, addr) &&
conn->port == port &&
- conn->purpose == purpose &&
- !conn->marked_for_close)
- return conn;
- });
- return NULL;
+ conn->purpose == purpose));
}
/** Return the stream with id <b>id</b> if it is not already marked for
@@ -4235,13 +4264,7 @@ connection_get_by_type_addr_port_purpose(int type,
connection_t *
connection_get_by_global_id(uint64_t id)
{
- smartlist_t *conns = get_connection_array();
- SMARTLIST_FOREACH(conns, connection_t *, conn,
- {
- if (conn->global_identifier == id)
- return conn;
- });
- return NULL;
+ CONN_GET_TEMPLATE(conn, conn->global_identifier == id);
}
/** Return a connection of type <b>type</b> that is not marked for close.
@@ -4249,13 +4272,7 @@ connection_get_by_global_id(uint64_t id)
connection_t *
connection_get_by_type(int type)
{
- smartlist_t *conns = get_connection_array();
- SMARTLIST_FOREACH(conns, connection_t *, conn,
- {
- if (conn->type == type && !conn->marked_for_close)
- return conn;
- });
- return NULL;
+ CONN_GET_TEMPLATE(conn, conn->type == type);
}
/** Return a connection of type <b>type</b> that is in state <b>state</b>,
@@ -4264,13 +4281,7 @@ connection_get_by_type(int type)
connection_t *
connection_get_by_type_state(int type, int state)
{
- smartlist_t *conns = get_connection_array();
- SMARTLIST_FOREACH(conns, connection_t *, conn,
- {
- if (conn->type == type && conn->state == state && !conn->marked_for_close)
- return conn;
- });
- return NULL;
+ CONN_GET_TEMPLATE(conn, conn->type == type && conn->state == state);
}
/** Return a connection of type <b>type</b> that has rendquery equal
@@ -4281,55 +4292,141 @@ connection_t *
connection_get_by_type_state_rendquery(int type, int state,
const char *rendquery)
{
- smartlist_t *conns = get_connection_array();
-
tor_assert(type == CONN_TYPE_DIR ||
type == CONN_TYPE_AP || type == CONN_TYPE_EXIT);
tor_assert(rendquery);
- SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn) {
- if (conn->type == type &&
- !conn->marked_for_close &&
- (!state || state == conn->state)) {
- if (type == CONN_TYPE_DIR &&
+ 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,
TO_DIR_CONN(conn)->rend_data->onion_address))
- return conn;
- else if (CONN_IS_EDGE(conn) &&
+ ||
+ (CONN_IS_EDGE(conn) &&
TO_EDGE_CONN(conn)->rend_data &&
!rend_cmp_service_ids(rendquery,
TO_EDGE_CONN(conn)->rend_data->onion_address))
- return conn;
- }
- } SMARTLIST_FOREACH_END(conn);
- return NULL;
+ ));
}
+#define CONN_FIRST_AND_FREE_TEMPLATE(sl) \
+ STMT_BEGIN \
+ if (smartlist_len(sl) > 0) { \
+ void *first_item = smartlist_get(sl, 0); \
+ smartlist_free(sl); \
+ return first_item; \
+ } else { \
+ smartlist_free(sl); \
+ return NULL; \
+ } \
+ STMT_END
+
/** Return a directory connection (if any one exists) that is fetching
- * the item described by <b>state</b>/<b>resource</b> */
+ * the item described by <b>purpose</b>/<b>resource</b>, otherwise return NULL.
+ */
dir_connection_t *
-connection_dir_get_by_purpose_and_resource(int purpose,
+connection_dir_get_by_purpose_and_resource(
+ int purpose,
const char *resource)
{
- smartlist_t *conns = get_connection_array();
+ smartlist_t *conns = connection_dir_list_by_purpose_and_resource(
+ purpose,
+ resource);
+ CONN_FIRST_AND_FREE_TEMPLATE(conns);
+}
- SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn) {
- dir_connection_t *dirconn;
- if (conn->type != CONN_TYPE_DIR || conn->marked_for_close ||
- conn->purpose != purpose)
- continue;
- dirconn = TO_DIR_CONN(conn);
- if (dirconn->requested_resource == NULL) {
- if (resource == NULL)
- return dirconn;
- } else if (resource) {
- if (0 == strcmp(resource, dirconn->requested_resource))
- return dirconn;
- }
- } SMARTLIST_FOREACH_END(conn);
+/** 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
+ * marked for close to be included in the list. */
+#define DIR_CONN_LIST_TEMPLATE(conn_var, conn_test, \
+ dirconn_var, dirconn_test) \
+ STMT_BEGIN \
+ smartlist_t *conns = get_connection_array(); \
+ smartlist_t *dir_conns = smartlist_new(); \
+ SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn_var) { \
+ if (conn_var && (conn_test) \
+ && conn_var->type == CONN_TYPE_DIR \
+ && !conn_var->marked_for_close) { \
+ dir_connection_t *dirconn_var = TO_DIR_CONN(conn_var); \
+ if (dirconn_var && (dirconn_test)) { \
+ smartlist_add(dir_conns, dirconn_var); \
+ } \
+ } \
+ } SMARTLIST_FOREACH_END(conn_var); \
+ return dir_conns; \
+ STMT_END
+
+/** Return a list of directory connections that are fetching the item
+ * described by <b>purpose</b>/<b>resource</b>. If there are none,
+ * return an empty list. This list must be freed using smartlist_free,
+ * but the pointers in it must not be freed.
+ * Note that this list should not be cached, as the pointers in it can be
+ * freed if their connections close. */
+smartlist_t *
+connection_dir_list_by_purpose_and_resource(
+ int purpose,
+ const char *resource)
+{
+ DIR_CONN_LIST_TEMPLATE(conn,
+ conn->purpose == purpose,
+ dirconn,
+ 0 == strcmp_opt(resource,
+ dirconn->requested_resource));
+}
- return NULL;
+/** Return a directory connection (if any one exists) that is fetching
+ * the item described by <b>purpose</b>/<b>resource</b>/<b>state</b>,
+ * otherwise return NULL. */
+dir_connection_t *
+connection_dir_get_by_purpose_resource_and_state(
+ int purpose,
+ const char *resource,
+ int state)
+{
+ smartlist_t *conns =
+ connection_dir_list_by_purpose_resource_and_state(
+ purpose,
+ resource,
+ state);
+ CONN_FIRST_AND_FREE_TEMPLATE(conns);
+}
+
+#undef CONN_FIRST_AND_FREE_TEMPLATE
+
+/** Return a list of directory connections that are fetching the item
+ * described by <b>purpose</b>/<b>resource</b>/<b>state</b>. If there are
+ * none, return an empty list. This list must be freed using smartlist_free,
+ * but the pointers in it must not be freed.
+ * Note that this list should not be cached, as the pointers in it can be
+ * freed if their connections close. */
+smartlist_t *
+connection_dir_list_by_purpose_resource_and_state(
+ int purpose,
+ const char *resource,
+ int state)
+{
+ DIR_CONN_LIST_TEMPLATE(conn,
+ conn->purpose == purpose && conn->state == state,
+ dirconn,
+ 0 == strcmp_opt(resource,
+ dirconn->requested_resource));
+}
+
+#undef DIR_CONN_LIST_TEMPLATE
+
+/** Return an arbitrary active OR connection that isn't <b>this_conn</b>.
+ *
+ * We use this to guess if we should tell the controller that we
+ * didn't manage to connect to any of our bridges. */
+static connection_t *
+connection_get_another_active_or_conn(const or_connection_t *this_conn)
+{
+ CONN_GET_TEMPLATE(conn,
+ conn != TO_CONN(this_conn) && conn->type == CONN_TYPE_OR);
}
/** Return 1 if there are any active OR connections apart from
@@ -4340,23 +4437,18 @@ connection_dir_get_by_purpose_and_resource(int purpose,
int
any_other_active_or_conns(const or_connection_t *this_conn)
{
- smartlist_t *conns = get_connection_array();
- SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn) {
- if (conn == TO_CONN(this_conn)) { /* don't consider this conn */
- continue;
- }
-
- if (conn->type == CONN_TYPE_OR &&
- !conn->marked_for_close) {
- log_debug(LD_DIR, "%s: Found an OR connection: %s",
- __func__, conn->address);
- return 1;
- }
- } SMARTLIST_FOREACH_END(conn);
+ connection_t *conn = connection_get_another_active_or_conn(this_conn);
+ if (conn != NULL) {
+ log_debug(LD_DIR, "%s: Found an OR connection: %s",
+ __func__, conn->address);
+ return 1;
+ }
return 0;
}
+#undef CONN_GET_TEMPLATE
+
/** Return 1 if <b>conn</b> is a listener conn, else return 0. */
int
connection_is_listener(connection_t *conn)
@@ -5012,3 +5104,34 @@ connection_free_all(void)
#endif
}
+/** Log a warning, and possibly emit a control event, that <b>received</b> came
+ * at a skewed time. <b>trusted</b> indicates that the <b>source</b> was one
+ * that we had more faith in and therefore the warning level should have higher
+ * severity.
+ */
+void
+clock_skew_warning(const connection_t *conn, long apparent_skew, int trusted,
+ log_domain_mask_t domain, const char *received,
+ const char *source)
+{
+ char dbuf[64];
+ char *ext_source = NULL;
+ format_time_interval(dbuf, sizeof(dbuf), apparent_skew);
+ if (conn)
+ tor_asprintf(&ext_source, "%s:%s:%d", source, conn->address, conn->port);
+ else
+ ext_source = tor_strdup(source);
+ log_fn(trusted ? LOG_WARN : LOG_INFO, domain,
+ "Received %s with skewed time (%s): "
+ "It seems that our clock is %s by %s, or that theirs is %s%s. "
+ "Tor requires an accurate clock to work: please check your time, "
+ "timezone, and date settings.", received, ext_source,
+ apparent_skew > 0 ? "ahead" : "behind", dbuf,
+ apparent_skew > 0 ? "behind" : "ahead",
+ (!conn || trusted) ? "" : ", or they are sending us the wrong time");
+ if (trusted)
+ control_event_general_status(LOG_WARN, "CLOCK_SKEW SKEW=%ld SOURCE=%s",
+ apparent_skew, ext_source);
+ tor_free(ext_source);
+}
+