aboutsummaryrefslogtreecommitdiff
path: root/src/or/connection_edge.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/or/connection_edge.c')
-rw-r--r--src/or/connection_edge.c287
1 files changed, 165 insertions, 122 deletions
diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c
index ded02e936..64f342993 100644
--- a/src/or/connection_edge.c
+++ b/src/or/connection_edge.c
@@ -10,6 +10,28 @@
**/
#include "or.h"
+#include "buffers.h"
+#include "circuitlist.h"
+#include "circuituse.h"
+#include "config.h"
+#include "connection.h"
+#include "connection_edge.h"
+#include "connection_or.h"
+#include "control.h"
+#include "dns.h"
+#include "dnsserv.h"
+#include "dirserv.h"
+#include "hibernate.h"
+#include "main.h"
+#include "policies.h"
+#include "reasons.h"
+#include "relay.h"
+#include "rendclient.h"
+#include "rendcommon.h"
+#include "rendservice.h"
+#include "rephist.h"
+#include "router.h"
+#include "routerlist.h"
#ifdef HAVE_LINUX_TYPES_H
#include <linux/types.h>
@@ -330,11 +352,13 @@ connection_edge_finished_connecting(edge_connection_t *edge_conn)
tor_assert(conn->state == EXIT_CONN_STATE_CONNECTING);
log_info(LD_EXIT,"Exit connection to %s:%u (%s) established.",
- escaped_safe_str(conn->address),conn->port,
+ escaped_safe_str(conn->address), conn->port,
safe_str(fmt_addr(&conn->addr)));
+ rep_hist_note_exit_stream_opened(conn->port);
+
conn->state = EXIT_CONN_STATE_OPEN;
- connection_watch_events(conn, EV_READ); /* stop writing, continue reading */
+ connection_watch_events(conn, READ_EVENT); /* stop writing, keep reading */
if (connection_wants_to_flush(conn)) /* in case there are any queued relay
* cells */
connection_start_writing(conn);
@@ -375,13 +399,16 @@ connection_edge_finished_connecting(edge_connection_t *edge_conn)
static int
compute_retry_timeout(edge_connection_t *conn)
{
+ int timeout = get_options()->CircuitStreamTimeout;
+ if (timeout) /* if our config options override the default, use them */
+ return timeout;
if (conn->num_socks_retries < 2) /* try 0 and try 1 */
return 10;
return 15;
}
/** Find all general-purpose AP streams waiting for a response that sent their
- * begin/resolve cell >=15 seconds ago. Detach from their current circuit, and
+ * begin/resolve cell too long ago. Detach from their current circuit, and
* mark their current circuit as unsuitable for new streams. Then call
* connection_ap_handshake_attach_circuit() to attach to a new circuit (if
* available) or launch a new one.
@@ -423,7 +450,8 @@ connection_ap_expire_beginning(void)
log_fn(severity, LD_APP,
"Tried for %d seconds to get a connection to %s:%d. "
"Giving up. (%s)",
- seconds_since_born, safe_str(conn->socks_request->address),
+ seconds_since_born,
+ safe_str_client(conn->socks_request->address),
conn->socks_request->port,
conn_state_to_string(CONN_TYPE_AP, conn->_base.state));
connection_mark_unattached_ap(conn, END_STREAM_REASON_TIMEOUT);
@@ -440,7 +468,7 @@ connection_ap_expire_beginning(void)
circ = circuit_get_by_edge_conn(conn);
if (!circ) { /* it's vanished? */
log_info(LD_APP,"Conn is waiting (address %s), but lost its circ.",
- safe_str(conn->socks_request->address));
+ safe_str_client(conn->socks_request->address));
connection_mark_unattached_ap(conn, END_STREAM_REASON_TIMEOUT);
continue;
}
@@ -450,7 +478,7 @@ connection_ap_expire_beginning(void)
"Rend stream is %d seconds late. Giving up on address"
" '%s.onion'.",
seconds_idle,
- safe_str(conn->socks_request->address));
+ safe_str_client(conn->socks_request->address));
connection_edge_end(conn, END_STREAM_REASON_TIMEOUT);
connection_mark_unattached_ap(conn, END_STREAM_REASON_TIMEOUT);
}
@@ -460,7 +488,8 @@ connection_ap_expire_beginning(void)
log_fn(cutoff < 15 ? LOG_INFO : severity, LD_APP,
"We tried for %d seconds to connect to '%s' using exit '%s'."
" Retrying on a new circuit.",
- seconds_idle, safe_str(conn->socks_request->address),
+ seconds_idle,
+ safe_str_client(conn->socks_request->address),
conn->cpath_layer ?
conn->cpath_layer->extend_info->nickname : "*unnamed*");
/* send an end down the circuit */
@@ -577,8 +606,8 @@ circuit_discard_optional_exit_enclaves(extend_info_t *info)
tor_assert(edge_conn->socks_request);
if (edge_conn->chosen_exit_optional) {
log_info(LD_APP, "Giving up on enclave exit '%s' for destination %s.",
- safe_str(edge_conn->chosen_exit_name),
- escaped_safe_str(edge_conn->socks_request->address));
+ safe_str_client(edge_conn->chosen_exit_name),
+ escaped_safe_str_client(edge_conn->socks_request->address));
edge_conn->chosen_exit_optional = 0;
tor_free(edge_conn->chosen_exit_name); /* clears it */
/* if this port is dangerous, warn or reject it now that we don't
@@ -683,7 +712,11 @@ addressmap_init(void)
static void
addressmap_ent_free(void *_ent)
{
- addressmap_entry_t *ent = _ent;
+ addressmap_entry_t *ent;
+ if (!_ent)
+ return;
+
+ ent = _ent;
tor_free(ent->new_address);
tor_free(ent);
}
@@ -692,7 +725,11 @@ addressmap_ent_free(void *_ent)
static void
addressmap_virtaddress_ent_free(void *_ent)
{
- virtaddress_entry_t *ent = _ent;
+ virtaddress_entry_t *ent;
+ if (!_ent)
+ return;
+
+ ent = _ent;
tor_free(ent->ipv4_address);
tor_free(ent->hostname_address);
tor_free(ent);
@@ -782,14 +819,11 @@ addressmap_clean(time_t now)
void
addressmap_free_all(void)
{
- if (addressmap) {
- strmap_free(addressmap, addressmap_ent_free);
- addressmap = NULL;
- }
- if (virtaddress_reversemap) {
- strmap_free(virtaddress_reversemap, addressmap_virtaddress_ent_free);
- virtaddress_reversemap = NULL;
- }
+ strmap_free(addressmap, addressmap_ent_free);
+ addressmap = NULL;
+
+ strmap_free(virtaddress_reversemap, addressmap_virtaddress_ent_free);
+ virtaddress_reversemap = NULL;
}
/** Look at address, and rewrite it until it doesn't want any
@@ -816,9 +850,9 @@ addressmap_rewrite(char *address, size_t maxlen, time_t *expires_out)
return (rewrites > 0); /* done, no rewrite needed */
}
- cp = tor_strdup(escaped_safe_str(ent->new_address));
+ cp = tor_strdup(escaped_safe_str_client(ent->new_address));
log_info(LD_APP, "Addressmap: rewriting %s to %s",
- escaped_safe_str(address), cp);
+ escaped_safe_str_client(address), cp);
if (ent->expires > 1 && ent->expires < expires)
expires = ent->expires;
tor_free(cp);
@@ -826,7 +860,7 @@ addressmap_rewrite(char *address, size_t maxlen, time_t *expires_out)
}
log_warn(LD_CONFIG,
"Loop detected: we've rewritten %s 16 times! Using it as-is.",
- escaped_safe_str(address));
+ escaped_safe_str_client(address));
/* it's fine to rewrite a rewrite, but don't loop forever */
if (expires_out)
*expires_out = TIME_MAX;
@@ -848,9 +882,9 @@ addressmap_rewrite_reverse(char *address, size_t maxlen, time_t *expires_out)
tor_snprintf(s, len, "REVERSE[%s]", address);
ent = strmap_get(addressmap, s);
if (ent) {
- cp = tor_strdup(escaped_safe_str(ent->new_address));
+ cp = tor_strdup(escaped_safe_str_client(ent->new_address));
log_info(LD_APP, "Rewrote reverse lookup %s -> %s",
- escaped_safe_str(s), cp);
+ escaped_safe_str_client(s), cp);
tor_free(cp);
strlcpy(address, ent->new_address, maxlen);
r = 1;
@@ -912,7 +946,9 @@ addressmap_register(const char *address, char *new_address, time_t expires,
if (expires > 1) {
log_info(LD_APP,"Temporary addressmap ('%s' to '%s') not performed, "
"since it's already mapped to '%s'",
- safe_str(address), safe_str(new_address), safe_str(ent->new_address));
+ safe_str_client(address),
+ safe_str_client(new_address),
+ safe_str_client(ent->new_address));
tor_free(new_address);
return;
}
@@ -931,7 +967,8 @@ addressmap_register(const char *address, char *new_address, time_t expires,
ent->source = source;
log_info(LD_CONFIG, "Addressmap: (re)mapped '%s' to '%s'",
- safe_str(address), safe_str(ent->new_address));
+ safe_str_client(address),
+ safe_str_client(ent->new_address));
control_event_address_mapped(address, ent->new_address, expires, NULL);
}
@@ -951,7 +988,8 @@ client_dns_incr_failures(const char *address)
if (ent->num_resolve_failures < SHORT_MAX)
++ent->num_resolve_failures; /* don't overflow */
log_info(LD_APP, "Address %s now has %d resolve failures.",
- safe_str(address), ent->num_resolve_failures);
+ safe_str_client(address),
+ ent->num_resolve_failures);
return ent->num_resolve_failures;
}
@@ -1230,8 +1268,10 @@ addressmap_register_virtual_address(int type, char *new_address)
log_warn(LD_BUG,
"Internal confusion: I thought that '%s' was mapped to by "
"'%s', but '%s' really maps to '%s'. This is a harmless bug.",
- safe_str(new_address), safe_str(*addrp), safe_str(*addrp),
- ent?safe_str(ent->new_address):"(nothing)");
+ safe_str_client(new_address),
+ safe_str_client(*addrp),
+ safe_str_client(*addrp),
+ ent?safe_str_client(ent->new_address):"(nothing)");
}
tor_free(*addrp);
@@ -1252,7 +1292,8 @@ addressmap_register_virtual_address(int type, char *new_address)
(type == RESOLVED_TYPE_IPV4) ?
vent->ipv4_address : vent->hostname_address));
log_info(LD_APP, "Map from %s to %s okay.",
- safe_str(*addrp),safe_str(new_address));
+ safe_str_client(*addrp),
+ safe_str_client(new_address));
}
#endif
@@ -1400,7 +1441,7 @@ connection_ap_handshake_rewrite_and_attach(edge_connection_t *conn,
tor_strlower(socks->address); /* normalize it */
strlcpy(orig_address, socks->address, sizeof(orig_address));
log_debug(LD_APP,"Client asked for %s:%d",
- safe_str(socks->address),
+ safe_str_client(socks->address),
socks->port);
if (socks->command == SOCKS_COMMAND_RESOLVE &&
@@ -1417,7 +1458,8 @@ connection_ap_handshake_rewrite_and_attach(edge_connection_t *conn,
RESOLVED_TYPE_IPV4, tor_strdup(socks->address));
tor_assert(new_addr);
log_info(LD_APP, "Automapping %s to %s",
- escaped_safe_str(socks->address), safe_str(new_addr));
+ escaped_safe_str_client(socks->address),
+ safe_str_client(new_addr));
strlcpy(socks->address, new_addr, sizeof(socks->address));
}
}
@@ -1473,7 +1515,7 @@ connection_ap_handshake_rewrite_and_attach(edge_connection_t *conn,
* information.
*/
log_warn(LD_APP,"Missing mapping for virtual address '%s'. Refusing.",
- socks->address); /* don't safe_str() this yet. */
+ safe_str_client(socks->address));
connection_mark_unattached_ap(conn, END_STREAM_REASON_INTERNAL);
return -1;
}
@@ -1481,11 +1523,12 @@ connection_ap_handshake_rewrite_and_attach(edge_connection_t *conn,
/* Parse the address provided by SOCKS. Modify it in-place if it
* specifies a hidden-service (.onion) or particular exit node (.exit).
*/
- addresstype = parse_extended_hostname(socks->address);
+ addresstype = parse_extended_hostname(socks->address,
+ remapped_to_exit || options->AllowDotExit);
if (addresstype == BAD_HOSTNAME) {
log_warn(LD_APP, "Invalid onion hostname %s; rejecting",
- safe_str(socks->address));
+ safe_str_client(socks->address));
control_event_client_status(LOG_WARN, "SOCKS_BAD_HOSTNAME HOSTNAME=%s",
escaped(socks->address));
connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
@@ -1494,7 +1537,7 @@ connection_ap_handshake_rewrite_and_attach(edge_connection_t *conn,
if (addresstype == EXIT_HOSTNAME) {
/* foo.exit -- modify conn->chosen_exit_node to specify the exit
- * node, and conn->address to hold only the address portion.*/
+ * node, and conn->address to hold only the address portion. */
char *s = strrchr(socks->address,'.');
tor_assert(!automap);
if (s) {
@@ -1505,7 +1548,7 @@ connection_ap_handshake_rewrite_and_attach(edge_connection_t *conn,
*s = 0;
} else {
log_warn(LD_APP,"Malformed exit address '%s.exit'. Refusing.",
- safe_str(socks->address));
+ safe_str_client(socks->address));
control_event_client_status(LOG_WARN, "SOCKS_BAD_HOSTNAME HOSTNAME=%s",
escaped(socks->address));
connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
@@ -1521,7 +1564,7 @@ connection_ap_handshake_rewrite_and_attach(edge_connection_t *conn,
} else {
log_warn(LD_APP,
"Unrecognized server in exit address '%s.exit'. Refusing.",
- safe_str(socks->address));
+ safe_str_client(socks->address));
connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
return -1;
}
@@ -1535,7 +1578,7 @@ connection_ap_handshake_rewrite_and_attach(edge_connection_t *conn,
escaped(socks->address));
log_warn(LD_APP,
"Destination '%s' seems to be an invalid hostname. Failing.",
- safe_str(socks->address));
+ safe_str_client(socks->address));
connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
return -1;
}
@@ -1544,18 +1587,6 @@ connection_ap_handshake_rewrite_and_attach(edge_connection_t *conn,
uint32_t answer;
struct in_addr in;
/* Reply to resolves immediately if we can. */
- if (strlen(socks->address) > RELAY_PAYLOAD_SIZE) {
- log_warn(LD_APP,"Address to be resolved is too large. Failing.");
- control_event_client_status(LOG_WARN, "SOCKS_BAD_HOSTNAME HOSTNAME=%s",
- escaped(socks->address));
- connection_ap_handshake_socks_resolved(conn,
- RESOLVED_TYPE_ERROR_TRANSIENT,
- 0,NULL,-1,TIME_MAX);
- connection_mark_unattached_ap(conn,
- END_STREAM_REASON_SOCKSPROTOCOL |
- END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
- return -1;
- }
if (tor_inet_aton(socks->address, &in)) { /* see if it's an IP already */
/* leave it in network order */
answer = in.s_addr;
@@ -1585,7 +1616,7 @@ connection_ap_handshake_rewrite_and_attach(edge_connection_t *conn,
if (r) {
log_info(LD_APP,
"Redirecting address %s to exit at enclave router %s",
- safe_str(socks->address), r->nickname);
+ safe_str_client(socks->address), r->nickname);
/* use the hex digest, not nickname, in case there are two
routers with this nickname */
conn->chosen_exit_name =
@@ -1649,12 +1680,12 @@ connection_ap_handshake_rewrite_and_attach(edge_connection_t *conn,
strlcpy(conn->rend_data->onion_address, socks->address,
sizeof(conn->rend_data->onion_address));
log_info(LD_REND,"Got a hidden service request for ID '%s'",
- safe_str(conn->rend_data->onion_address));
+ safe_str_client(conn->rend_data->onion_address));
/* see if we already have it cached */
r = rend_cache_lookup_entry(conn->rend_data->onion_address, -1, &entry);
if (r<0) {
log_warn(LD_BUG,"Invalid service name '%s'",
- safe_str(conn->rend_data->onion_address));
+ safe_str_client(conn->rend_data->onion_address));
connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
return -1;
}
@@ -1676,32 +1707,15 @@ connection_ap_handshake_rewrite_and_attach(edge_connection_t *conn,
if (r==0) {
conn->_base.state = AP_CONN_STATE_RENDDESC_WAIT;
log_info(LD_REND, "Unknown descriptor %s. Fetching.",
- safe_str(conn->rend_data->onion_address));
- /* Fetch both, v0 and v2 rend descriptors in parallel. Use whichever
- * arrives first. Exception: When using client authorization, only
- * fetch v2 descriptors.*/
+ safe_str_client(conn->rend_data->onion_address));
rend_client_refetch_v2_renddesc(conn->rend_data);
- if (conn->rend_data->auth_type == REND_NO_AUTH)
- rend_client_refetch_renddesc(conn->rend_data->onion_address);
} else { /* r > 0 */
- if (now - entry->received < NUM_SECONDS_BEFORE_HS_REFETCH) {
- conn->_base.state = AP_CONN_STATE_CIRCUIT_WAIT;
- log_info(LD_REND, "Descriptor is here and fresh enough. Great.");
- if (connection_ap_handshake_attach_circuit(conn) < 0) {
- if (!conn->_base.marked_for_close)
- connection_mark_unattached_ap(conn, END_STREAM_REASON_CANT_ATTACH);
- return -1;
- }
- } else {
- conn->_base.state = AP_CONN_STATE_RENDDESC_WAIT;
- log_info(LD_REND, "Stale descriptor %s. Re-fetching.",
- safe_str(conn->rend_data->onion_address));
- /* Fetch both, v0 and v2 rend descriptors in parallel. Use whichever
- * arrives first. Exception: When using client authorization, only
- * fetch v2 descriptors.*/
- rend_client_refetch_v2_renddesc(conn->rend_data);
- if (conn->rend_data->auth_type == REND_NO_AUTH)
- rend_client_refetch_renddesc(conn->rend_data->onion_address);
+ conn->_base.state = AP_CONN_STATE_CIRCUIT_WAIT;
+ log_info(LD_REND, "Descriptor is here. Great.");
+ if (connection_ap_handshake_attach_circuit(conn) < 0) {
+ if (!conn->_base.marked_for_close)
+ connection_mark_unattached_ap(conn, END_STREAM_REASON_CANT_ATTACH);
+ return -1;
}
}
return 0;
@@ -1889,14 +1903,6 @@ connection_ap_handshake_process_socks(edge_connection_t *conn)
return -1;
} /* else socks handshake is done, continue processing */
- if (hostname_is_noconnect_address(socks->address))
- {
- control_event_stream_status(conn, STREAM_EVENT_NEW, 0);
- control_event_stream_status(conn, STREAM_EVENT_CLOSED, 0);
- connection_mark_unattached_ap(conn, END_STREAM_REASON_DONE);
- return -1;
- }
-
if (SOCKS_COMMAND_IS_CONNECT(socks->command))
control_event_stream_status(conn, STREAM_EVENT_NEW, 0);
else
@@ -2044,7 +2050,7 @@ get_unique_stream_id_by_circ(origin_circuit_t *circ)
streamid_t test_stream_id;
uint32_t attempts=0;
-again:
+ again:
test_stream_id = circ->next_stream_id++;
if (++attempts > 1<<16) {
/* Make sure we don't loop forever if all stream_id's are used. */
@@ -2160,7 +2166,7 @@ connection_ap_handshake_send_resolve(edge_connection_t *ap_conn)
r = tor_addr_parse_reverse_lookup_name(&addr, a, AF_INET, 1);
if (r <= 0) {
log_warn(LD_APP, "Rejecting ill-formed reverse lookup of %s",
- safe_str(a));
+ safe_str_client(a));
connection_mark_unattached_ap(ap_conn, END_STREAM_REASON_INTERNAL);
return -1;
}
@@ -2168,7 +2174,7 @@ connection_ap_handshake_send_resolve(edge_connection_t *ap_conn)
r = tor_addr_to_reverse_lookup_name(inaddr_buf, sizeof(inaddr_buf), &addr);
if (r < 0) {
log_warn(LD_BUG, "Couldn't generate reverse lookup hostname of %s",
- safe_str(a));
+ safe_str_client(a));
connection_mark_unattached_ap(ap_conn, END_STREAM_REASON_INTERNAL);
return -1;
}
@@ -2178,12 +2184,6 @@ connection_ap_handshake_send_resolve(edge_connection_t *ap_conn)
tor_assert(payload_len <= (int)sizeof(inaddr_buf));
}
- if (payload_len > RELAY_PAYLOAD_SIZE) {
- /* This should be impossible: we don't accept addresses this big. */
- connection_mark_unattached_ap(ap_conn, END_STREAM_REASON_INTERNAL);
- return -1;
- }
-
log_debug(LD_APP,
"Sending relay cell to begin stream %d.", ap_conn->stream_id);
@@ -2215,7 +2215,8 @@ connection_ap_make_link(char *address, uint16_t port,
edge_connection_t *conn;
log_info(LD_APP,"Making internal %s tunnel to %s:%d ...",
- want_onehop ? "direct" : "anonymized" , safe_str(address),port);
+ want_onehop ? "direct" : "anonymized",
+ safe_str_client(address), port);
conn = edge_connection_new(CONN_TYPE_AP, AF_INET);
conn->_base.linked = 1; /* so that we can add it safely below. */
@@ -2526,16 +2527,28 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
tor_free(address);
return 0;
}
- if (or_circ && or_circ->is_first_hop &&
- !get_options()->AllowSingleHopExits) {
+ if (or_circ && or_circ->p_conn && !get_options()->AllowSingleHopExits &&
+ (or_circ->is_first_hop ||
+ (!connection_or_digest_is_known_relay(
+ or_circ->p_conn->identity_digest) &&
+// XXX022 commented out so we can test it first in 0.2.2.11 -RD
+// networkstatus_get_param(NULL, "refuseunknownexits", 1)))) {
+ get_options()->RefuseUnknownExits))) {
/* Don't let clients use us as a single-hop proxy, unless the user
- * has explicitly allowed that in the config. It attracts attackers
+ * has explicitly allowed that in the config. It attracts attackers
* and users who'd be better off with, well, single-hop proxies.
*/
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Attempt to open a stream on first hop of circuit. Closing.");
+// log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ log_notice(LD_PROTOCOL,
+ "Attempt by %s to open a stream %s. Closing.",
+ safe_str(or_circ->p_conn->_base.address),
+ or_circ->is_first_hop ? "on first hop of circuit" :
+ "from unknown relay");
relay_send_end_cell_from_edge(rh.stream_id, circ,
- END_STREAM_REASON_TORPROTOCOL, NULL);
+ or_circ->is_first_hop ?
+ END_STREAM_REASON_TORPROTOCOL :
+ END_STREAM_REASON_MISC,
+ NULL);
tor_free(address);
return 0;
}
@@ -2566,6 +2579,11 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
log_debug(LD_EXIT,"Creating new exit connection.");
n_stream = edge_connection_new(CONN_TYPE_EXIT, AF_INET);
+
+ /* Remember the tunneled request ID in the new edge connection, so that
+ * we can measure download times. */
+ TO_CONN(n_stream)->dirreq_id = circ->dirreq_id;
+
n_stream->_base.purpose = EXIT_PURPOSE_CONNECT;
n_stream->stream_id = rh.stream_id;
@@ -2596,7 +2614,7 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
log_debug(LD_REND,"Finished assigning addr/port");
n_stream->cpath_layer = origin_circ->cpath->prev; /* link it */
- /* add it into the linked list of n_streams on this circuit */
+ /* add it into the linked list of p_streams on this circuit */
n_stream->next_stream = origin_circ->p_streams;
n_stream->on_circuit = circ;
origin_circ->p_streams = n_stream;
@@ -2623,7 +2641,7 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
if (rh.command == RELAY_COMMAND_BEGIN_DIR) {
tor_assert(or_circ);
if (or_circ->p_conn && !tor_addr_is_null(&or_circ->p_conn->real_addr))
- tor_addr_assign(&n_stream->_base.addr, &or_circ->p_conn->real_addr);
+ tor_addr_copy(&n_stream->_base.addr, &or_circ->p_conn->real_addr);
return connection_exit_connect_dir(n_stream);
}
@@ -2713,7 +2731,7 @@ connection_exit_connect(edge_connection_t *edge_conn)
if (!connection_edge_is_rendezvous_stream(edge_conn) &&
router_compare_to_my_exit_policy(edge_conn)) {
log_info(LD_EXIT,"%s:%d failed exit policy. Closing.",
- escaped_safe_str(conn->address), conn->port);
+ escaped_safe_str_client(conn->address), conn->port);
connection_edge_end(edge_conn, END_STREAM_REASON_EXITPOLICY);
circuit_detach_stream(circuit_get_by_edge_conn(edge_conn), edge_conn);
connection_free(conn);
@@ -2735,7 +2753,7 @@ connection_exit_connect(edge_connection_t *edge_conn)
case 0:
conn->state = EXIT_CONN_STATE_CONNECTING;
- connection_watch_events(conn, EV_WRITE | EV_READ);
+ connection_watch_events(conn, READ_EVENT | WRITE_EVENT);
/* writable indicates finish;
* readable/error indicates broken link in windows-land. */
return;
@@ -2748,7 +2766,7 @@ connection_exit_connect(edge_connection_t *edge_conn)
log_warn(LD_BUG,"newly connected conn had data waiting!");
// connection_start_writing(conn);
}
- connection_watch_events(conn, EV_READ);
+ connection_watch_events(conn, READ_EVENT);
/* also, deliver a 'connected' cell back through the circuit. */
if (connection_edge_is_rendezvous_stream(edge_conn)) {
@@ -2795,13 +2813,17 @@ connection_exit_connect_dir(edge_connection_t *exitconn)
dirconn = dir_connection_new(AF_INET);
- tor_addr_assign(&dirconn->_base.addr, &exitconn->_base.addr);
+ tor_addr_copy(&dirconn->_base.addr, &exitconn->_base.addr);
dirconn->_base.port = 0;
dirconn->_base.address = tor_strdup(exitconn->_base.address);
dirconn->_base.type = CONN_TYPE_DIR;
dirconn->_base.purpose = DIR_PURPOSE_SERVER;
dirconn->_base.state = DIR_CONN_STATE_SERVER_COMMAND_WAIT;
+ /* Note that the new dir conn belongs to the same tunneled request as
+ * the edge conn, so that we can measure download times. */
+ TO_CONN(dirconn)->dirreq_id = TO_CONN(exitconn)->dirreq_id;
+
connection_link_connections(TO_CONN(dirconn), TO_CONN(exitconn));
if (connection_add(TO_CONN(exitconn))<0) {
@@ -2852,10 +2874,16 @@ connection_edge_is_rendezvous_stream(edge_connection_t *conn)
* to exit from it, or 0 if it probably will not allow it.
* (We might be uncertain if conn's destination address has not yet been
* resolved.)
+ *
+ * If <b>excluded_means_no</b> is 1 and Exclude*Nodes is set and excludes
+ * this relay, return 0.
*/
int
-connection_ap_can_use_exit(edge_connection_t *conn, routerinfo_t *exit)
+connection_ap_can_use_exit(edge_connection_t *conn, routerinfo_t *exit,
+ int excluded_means_no)
{
+ or_options_t *options = get_options();
+
tor_assert(conn);
tor_assert(conn->_base.type == CONN_TYPE_AP);
tor_assert(conn->socks_request);
@@ -2901,20 +2929,35 @@ connection_ap_can_use_exit(edge_connection_t *conn, routerinfo_t *exit)
if (!conn->chosen_exit_name && policy_is_reject_star(exit->exit_policy))
return 0;
}
+ if (options->_ExcludeExitNodesUnion &&
+ (options->StrictNodes || excluded_means_no) &&
+ routerset_contains_router(options->_ExcludeExitNodesUnion, exit)) {
+ /* If we are trying to avoid this node as exit, and we have StrictNodes
+ * set, then this is not a suitable exit. Refuse it.
+ *
+ * If we don't have StrictNodes set, then this function gets called in
+ * two contexts. First, we've got a circuit open and we want to know
+ * whether we can use it. In that case, we somehow built this circuit
+ * despite having the last hop in ExcludeExitNodes, so we should be
+ * willing to use it. Second, we are evaluating whether this is an
+ * acceptable exit for a new circuit. In that case, skip it. */
+ return 0;
+ }
+
return 1;
}
/** If address is of the form "y.onion" with a well-formed handle y:
* Put a NUL after y, lower-case it, and return ONION_HOSTNAME.
*
- * If address is of the form "y.exit":
+ * If address is of the form "y.exit" and <b>allowdotexit</b> is true:
* Put a NUL after y and return EXIT_HOSTNAME.
*
* Otherwise:
* Return NORMAL_HOSTNAME and change nothing.
*/
hostname_type_t
-parse_extended_hostname(char *address)
+parse_extended_hostname(char *address, int allowdotexit)
{
char *s;
char query[REND_SERVICE_ID_LEN_BASE32+1];
@@ -2923,8 +2966,16 @@ parse_extended_hostname(char *address)
if (!s)
return NORMAL_HOSTNAME; /* no dot, thus normal */
if (!strcmp(s+1,"exit")) {
- *s = 0; /* NUL-terminate it */
- return EXIT_HOSTNAME; /* .exit */
+ if (allowdotexit) {
+ *s = 0; /* NUL-terminate it */
+ return EXIT_HOSTNAME; /* .exit */
+ } else {
+ log_warn(LD_APP, "The \".exit\" notation is disabled in Tor due to "
+ "security risks. Set AllowDotExit in your torrc to enable "
+ "it.");
+ /* FFFF send a controller event too to notify Vidalia users */
+ return BAD_HOSTNAME;
+ }
}
if (strcmp(s+1,"onion"))
return NORMAL_HOSTNAME; /* neither .exit nor .onion, thus normal */
@@ -2937,17 +2988,9 @@ parse_extended_hostname(char *address)
if (rend_valid_service_id(query)) {
return ONION_HOSTNAME; /* success */
}
-failed:
+ failed:
/* otherwise, return to previous state and return 0 */
*s = '.';
return BAD_HOSTNAME;
}
-/** Check if the address is of the form "y.noconnect"
- */
-int
-hostname_is_noconnect_address(const char *address)
-{
- return ! strcasecmpend(address, ".noconnect");
-}
-