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.c538
1 files changed, 373 insertions, 165 deletions
diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c
index 0ec2002af..7828f1638 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>
@@ -125,7 +147,7 @@ connection_edge_process_inbuf(edge_connection_t *conn, int package_partial)
return 0;
case AP_CONN_STATE_OPEN:
case EXIT_CONN_STATE_OPEN:
- if (connection_edge_package_raw_inbuf(conn, package_partial) < 0) {
+ if (connection_edge_package_raw_inbuf(conn, package_partial, NULL) < 0) {
/* (We already sent an end cell if possible) */
connection_mark_for_close(TO_CONN(conn));
return -1;
@@ -279,6 +301,23 @@ connection_edge_end_errno(edge_connection_t *conn)
return connection_edge_end(conn, reason);
}
+/** We just wrote some data to <b>conn</b>; act appropriately.
+ *
+ * (That is, if it's open, consider sending a stream-level sendme cell if we
+ * have just flushed enough.)
+ */
+int
+connection_edge_flushed_some(edge_connection_t *conn)
+{
+ switch (conn->_base.state) {
+ case AP_CONN_STATE_OPEN:
+ case EXIT_CONN_STATE_OPEN:
+ connection_edge_consider_sending_sendme(conn);
+ break;
+ }
+ return 0;
+}
+
/** Connection <b>conn</b> has finished writing and has no bytes left on
* its outbuf.
*
@@ -330,11 +369,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 +416,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 +467,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 +485,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 +495,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 +505,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 */
@@ -471,6 +517,7 @@ connection_ap_expire_beginning(void)
/* kludge to make us not try this circuit again, yet to allow
* current streams on it to survive if they can: make it
* unattractive to use for new streams */
+ /* XXXX023 this is a kludgy way to do this. */
tor_assert(circ->timestamp_dirty);
circ->timestamp_dirty -= options->MaxCircuitDirtiness;
/* give our stream another 'cutoff' seconds to try */
@@ -511,7 +558,7 @@ connection_ap_attach_pending(void)
/** Tell any AP streams that are waiting for a one-hop tunnel to
* <b>failed_digest</b> that they are going to fail. */
-/* XXX022 We should get rid of this function, and instead attach
+/* XXX023 We should get rid of this function, and instead attach
* one-hop streams to circ->p_streams so they get marked in
* circuit_mark_for_close like normal p_streams. */
void
@@ -577,8 +624,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 +730,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 +743,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);
@@ -744,7 +799,8 @@ clear_trackexithost_mappings(const char *exitname)
tor_strlower(suffix);
STRMAP_FOREACH_MODIFY(addressmap, address, addressmap_entry_t *, ent) {
- if (ent->source == ADDRMAPSRC_TRACKEXIT && !strcmpend(address, suffix)) {
+ if (ent->source == ADDRMAPSRC_TRACKEXIT &&
+ !strcmpend(ent->new_address, suffix)) {
addressmap_ent_remove(address, ent);
MAP_DEL_CURRENT(address);
}
@@ -753,6 +809,101 @@ clear_trackexithost_mappings(const char *exitname)
tor_free(suffix);
}
+/** Remove all TRACKEXIT mappings from the addressmap for which the target
+ * host is unknown or no longer allowed, or for which the source address
+ * is no longer in trackexithosts. */
+void
+addressmap_clear_excluded_trackexithosts(or_options_t *options)
+{
+ const routerset_t *allow_nodes = options->ExitNodes;
+ const routerset_t *exclude_nodes = options->_ExcludeExitNodesUnion;
+
+ if (!addressmap)
+ return;
+ if (routerset_is_empty(allow_nodes))
+ allow_nodes = NULL;
+ if (allow_nodes == NULL && routerset_is_empty(exclude_nodes))
+ return;
+
+ STRMAP_FOREACH_MODIFY(addressmap, address, addressmap_entry_t *, ent) {
+ size_t len;
+ const char *target = ent->new_address, *dot;
+ char *nodename;
+ routerinfo_t *ri; /* XXX023 Use node_t. */
+
+ if (strcmpend(target, ".exit")) {
+ /* Not a .exit mapping */
+ continue;
+ } else if (ent->source != ADDRMAPSRC_TRACKEXIT) {
+ /* Not a trackexit mapping. */
+ continue;
+ }
+ len = strlen(target);
+ if (len < 6)
+ continue; /* malformed. */
+ dot = target + len - 6; /* dot now points to just before .exit */
+ dot = strrchr(dot, '.'); /* dot now points to the . before .exit or NULL */
+ if (!dot) {
+ nodename = tor_strndup(target, len-5);
+ } else {
+ nodename = tor_strndup(dot+1, strlen(dot+1)-5);
+ }
+ ri = router_get_by_nickname(nodename, 0);
+ tor_free(nodename);
+ if (!ri ||
+ (allow_nodes && !routerset_contains_router(allow_nodes, ri)) ||
+ routerset_contains_router(exclude_nodes, ri) ||
+ !hostname_in_track_host_exits(options, address)) {
+ /* We don't know this one, or we want to be rid of it. */
+ addressmap_ent_remove(address, ent);
+ MAP_DEL_CURRENT(address);
+ }
+ } STRMAP_FOREACH_END;
+}
+
+/** Remove all AUTOMAP mappings from the addressmap for which the
+ * source address no longer matches AutomapHostsSuffixes, which is
+ * no longer allowed by AutomapHostsOnResolve, or for which the
+ * target address is no longer in the virtual network. */
+void
+addressmap_clear_invalid_automaps(or_options_t *options)
+{
+ int clear_all = !options->AutomapHostsOnResolve;
+ const smartlist_t *suffixes = options->AutomapHostsSuffixes;
+
+ if (!addressmap)
+ return;
+
+ if (!suffixes)
+ clear_all = 1; /* This should be impossible, but let's be sure. */
+
+ STRMAP_FOREACH_MODIFY(addressmap, src_address, addressmap_entry_t *, ent) {
+ int remove = clear_all;
+ if (ent->source != ADDRMAPSRC_AUTOMAP)
+ continue; /* not an automap mapping. */
+
+ if (!remove) {
+ int suffix_found = 0;
+ SMARTLIST_FOREACH(suffixes, const char *, suffix, {
+ if (!strcasecmpend(src_address, suffix)) {
+ suffix_found = 1;
+ break;
+ }
+ });
+ if (!suffix_found)
+ remove = 1;
+ }
+
+ if (!remove && ! address_is_in_virtual_range(ent->new_address))
+ remove = 1;
+
+ if (remove) {
+ addressmap_ent_remove(src_address, ent);
+ MAP_DEL_CURRENT(src_address);
+ }
+ } STRMAP_FOREACH_END;
+}
+
/** Remove all entries from the addressmap that were set via the
* configuration file or the command line. */
void
@@ -782,14 +933,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 +964,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 +974,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 +996,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 +1060,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 +1081,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 +1102,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;
}
@@ -1247,8 +1399,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);
@@ -1261,7 +1415,7 @@ addressmap_register_virtual_address(int type, char *new_address)
log_info(LD_APP, "Registering map from %s to %s", *addrp, new_address);
if (vent_needs_to_be_added)
strmap_set(virtaddress_reversemap, new_address, vent);
- addressmap_register(*addrp, new_address, 2, ADDRMAPSRC_CONTROLLER);
+ addressmap_register(*addrp, new_address, 2, ADDRMAPSRC_AUTOMAP);
#if 0
{
@@ -1276,7 +1430,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
@@ -1391,6 +1546,26 @@ consider_plaintext_ports(edge_connection_t *conn, uint16_t port)
* different one? */
#define TRACKHOSTEXITS_RETRIES 5
+/** Call connection_ap_handshake_rewrite_and_attach() unless a controller
+ * asked us to leave streams unattached. Return 0 in that case.
+ *
+ * See connection_ap_handshake_rewrite_and_attach()'s
+ * documentation for arguments and return value.
+ */
+int
+connection_ap_rewrite_and_attach_if_allowed(edge_connection_t *conn,
+ origin_circuit_t *circ,
+ crypt_path_t *cpath)
+{
+ or_options_t *options = get_options();
+
+ if (options->LeaveStreamsUnattached) {
+ conn->_base.state = AP_CONN_STATE_CONTROLLER_WAIT;
+ return 0;
+ }
+ return connection_ap_handshake_rewrite_and_attach(conn, circ, cpath);
+}
+
/** Connection <b>conn</b> just finished its socks handshake, or the
* controller asked us to take care of it. If <b>circ</b> is defined,
* then that's where we'll want to attach it. Otherwise we have to
@@ -1415,16 +1590,20 @@ connection_ap_handshake_rewrite_and_attach(edge_connection_t *conn,
hostname_type_t addresstype;
or_options_t *options = get_options();
struct in_addr addr_tmp;
+ /* We set this to true if this is an address we should automatically
+ * remap to a local address in VirtualAddrNetwork */
int automap = 0;
char orig_address[MAX_SOCKS_ADDR_LEN];
time_t map_expires = TIME_MAX;
+ /* This will be set to true iff the address starts out as a non-.exit
+ address, and we remap it to one because of an entry in the addressmap. */
int remapped_to_exit = 0;
time_t now = time(NULL);
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 &&
@@ -1446,7 +1625,8 @@ connection_ap_handshake_rewrite_and_attach(edge_connection_t *conn,
return -1;
}
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));
}
}
@@ -1503,7 +1683,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;
}
@@ -1511,11 +1691,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);
@@ -1524,38 +1705,61 @@ 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,'.');
+
+ /* If StrictNodes is not set, then .exit overrides ExcludeNodes. */
+ routerset_t *excludeset = options->StrictNodes ?
+ options->_ExcludeExitNodesUnion : options->ExcludeExitNodes;
+ /*XXX023 make this a node_t. */
+ routerinfo_t *router;
+
tor_assert(!automap);
if (s) {
+ /* The address was of the form "(stuff).(name).exit */
if (s[1] != '\0') {
conn->chosen_exit_name = tor_strdup(s+1);
+ router = router_get_by_nickname(conn->chosen_exit_name, 1);
if (remapped_to_exit) /* 5 tries before it expires the addressmap */
conn->chosen_exit_retries = TRACKHOSTEXITS_RETRIES;
*s = 0;
} else {
+ /* Oops, the address was (stuff)..exit. That's not okay. */
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);
return -1;
}
} else {
- routerinfo_t *r;
+ /* It looks like they just asked for "foo.exit". */
conn->chosen_exit_name = tor_strdup(socks->address);
- r = router_get_by_nickname(conn->chosen_exit_name, 1);
- *socks->address = 0;
- if (r) {
- strlcpy(socks->address, r->address, sizeof(socks->address));
- } else {
- log_warn(LD_APP,
- "Unrecognized server in exit address '%s.exit'. Refusing.",
- safe_str(socks->address));
- connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
- return -1;
+ router = router_get_by_nickname(conn->chosen_exit_name, 1);
+ if (router) {
+ *socks->address = 0;
+ strlcpy(socks->address, router->address, sizeof(socks->address));
}
}
+ /* Now make sure that the chosen exit exists... */
+ if (!router) {
+ log_warn(LD_APP,
+ "Unrecognized relay in exit address '%s.exit'. Refusing.",
+ safe_str_client(socks->address));
+ connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
+ return -1;
+ }
+ /* ...and make sure that it isn't excluded. */
+ if (routerset_contains_router(excludeset, router)) {
+ log_warn(LD_APP,
+ "Excluded relay in exit address '%s.exit'. Refusing.",
+ safe_str_client(socks->address));
+ connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
+ return -1;
+ }
+ /* XXXX022-1090 Should we also allow foo.bar.exit if ExitNodes is set and
+ Bar is not listed in it? I say yes, but our revised manpage branch
+ implies no. */
}
if (addresstype != ONION_HOSTNAME) {
@@ -1565,7 +1769,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;
}
@@ -1574,18 +1778,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;
@@ -1608,6 +1800,28 @@ connection_ap_handshake_rewrite_and_attach(edge_connection_t *conn,
connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
return -1;
}
+ if (options->ClientRejectInternalAddresses &&
+ !conn->use_begindir && !conn->chosen_exit_name && !circ) {
+ tor_addr_t addr;
+ if (tor_addr_from_str(&addr, socks->address) >= 0 &&
+ tor_addr_is_internal(&addr, 0)) {
+ /* If this is an explicit private address with no chosen exit node,
+ * then we really don't want to try to connect to it. That's
+ * probably an error. */
+ if (conn->is_transparent_ap) {
+ log_warn(LD_NET,
+ "Rejecting request for anonymous connection to private "
+ "address %s on a TransPort or NATDPort. Possible loop "
+ "in your NAT rules?", safe_str_client(socks->address));
+ } else {
+ log_warn(LD_NET,
+ "Rejecting SOCKS request for anonymous connection to "
+ "private address %s", safe_str_client(socks->address));
+ }
+ connection_mark_unattached_ap(conn, END_STREAM_REASON_PRIVATE_ADDR);
+ return -1;
+ }
+ }
if (!conn->use_begindir && !conn->chosen_exit_name && !circ) {
/* see if we can find a suitable enclave exit */
@@ -1616,7 +1830,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 =
@@ -1680,12 +1894,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;
}
@@ -1707,32 +1921,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;
@@ -1920,24 +2117,12 @@ 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
control_event_stream_status(conn, STREAM_EVENT_NEW_RESOLVE, 0);
- if (options->LeaveStreamsUnattached) {
- conn->_base.state = AP_CONN_STATE_CONTROLLER_WAIT;
- return 0;
- }
- return connection_ap_handshake_rewrite_and_attach(conn, NULL, NULL);
+ return connection_ap_rewrite_and_attach_if_allowed(conn, NULL, NULL);
}
/** connection_init_accepted_conn() found a new trans AP conn.
@@ -1951,7 +2136,6 @@ int
connection_ap_process_transparent(edge_connection_t *conn)
{
socks_request_t *socks;
- or_options_t *options = get_options();
tor_assert(conn);
tor_assert(conn->_base.type == CONN_TYPE_AP);
@@ -1975,11 +2159,7 @@ connection_ap_process_transparent(edge_connection_t *conn)
control_event_stream_status(conn, STREAM_EVENT_NEW, 0);
- if (options->LeaveStreamsUnattached) {
- conn->_base.state = AP_CONN_STATE_CONTROLLER_WAIT;
- return 0;
- }
- return connection_ap_handshake_rewrite_and_attach(conn, NULL, NULL);
+ return connection_ap_rewrite_and_attach_if_allowed(conn, NULL, NULL);
}
/** connection_edge_process_inbuf() found a conn in state natd_wait. See if
@@ -2000,7 +2180,6 @@ connection_ap_process_natd(edge_connection_t *conn)
size_t tlen = 30;
int err, port_ok;
socks_request_t *socks;
- or_options_t *options = get_options();
tor_assert(conn);
tor_assert(conn->_base.type == CONN_TYPE_AP);
@@ -2016,13 +2195,13 @@ connection_ap_process_natd(edge_connection_t *conn)
if (err == 0)
return 0;
if (err < 0) {
- log_warn(LD_APP,"Natd handshake failed (DEST too long). Closing");
+ log_warn(LD_APP,"NATD handshake failed (DEST too long). Closing");
connection_mark_unattached_ap(conn, END_STREAM_REASON_INVALID_NATD_DEST);
return -1;
}
if (strcmpstart(tmp_buf, "[DEST ")) {
- log_warn(LD_APP,"Natd handshake was ill-formed; closing. The client "
+ log_warn(LD_APP,"NATD handshake was ill-formed; closing. The client "
"said: %s",
escaped(tmp_buf));
connection_mark_unattached_ap(conn, END_STREAM_REASON_INVALID_NATD_DEST);
@@ -2031,7 +2210,7 @@ connection_ap_process_natd(edge_connection_t *conn)
daddr = tbuf = &tmp_buf[0] + 6; /* after end of "[DEST " */
if (!(tbuf = strchr(tbuf, ' '))) {
- log_warn(LD_APP,"Natd handshake was ill-formed; closing. The client "
+ log_warn(LD_APP,"NATD handshake was ill-formed; closing. The client "
"said: %s",
escaped(tmp_buf));
connection_mark_unattached_ap(conn, END_STREAM_REASON_INVALID_NATD_DEST);
@@ -2045,7 +2224,7 @@ connection_ap_process_natd(edge_connection_t *conn)
socks->port = (uint16_t)
tor_parse_long(tbuf, 10, 1, 65535, &port_ok, &daddr);
if (!port_ok) {
- log_warn(LD_APP,"Natd handshake failed; port %s is ill-formed or out "
+ log_warn(LD_APP,"NATD handshake failed; port %s is ill-formed or out "
"of range.", escaped(tbuf));
connection_mark_unattached_ap(conn, END_STREAM_REASON_INVALID_NATD_DEST);
return -1;
@@ -2056,13 +2235,9 @@ connection_ap_process_natd(edge_connection_t *conn)
control_event_stream_status(conn, STREAM_EVENT_NEW, 0);
- if (options->LeaveStreamsUnattached) {
- conn->_base.state = AP_CONN_STATE_CONTROLLER_WAIT;
- return 0;
- }
conn->_base.state = AP_CONN_STATE_CIRCUIT_WAIT;
- return connection_ap_handshake_rewrite_and_attach(conn, NULL, NULL);
+ return connection_ap_rewrite_and_attach_if_allowed(conn, NULL, NULL);
}
/** Iterate over the two bytes of stream_id until we get one that is not
@@ -2075,7 +2250,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. */
@@ -2112,8 +2287,14 @@ connection_ap_handshake_send_begin(edge_connection_t *ap_conn)
ap_conn->stream_id = get_unique_stream_id_by_circ(circ);
if (ap_conn->stream_id==0) {
+ /* XXXX023 Instead of closing this stream, we should make it get
+ * retried on another circuit. */
connection_mark_unattached_ap(ap_conn, END_STREAM_REASON_INTERNAL);
- circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_RESOURCELIMIT);
+
+ /* Mark this circuit "unusable for new streams". */
+ /* XXXX023 this is a kludgy way to do this. */
+ tor_assert(circ->_base.timestamp_dirty);
+ circ->_base.timestamp_dirty -= get_options()->MaxCircuitDirtiness;
return -1;
}
@@ -2171,9 +2352,14 @@ connection_ap_handshake_send_resolve(edge_connection_t *ap_conn)
ap_conn->stream_id = get_unique_stream_id_by_circ(circ);
if (ap_conn->stream_id==0) {
+ /* XXXX023 Instead of closing this stream, we should make it get
+ * retried on another circuit. */
connection_mark_unattached_ap(ap_conn, END_STREAM_REASON_INTERNAL);
- /*XXXX022 _close_ the circuit because it's full? That sounds dumb. */
- circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_RESOURCELIMIT);
+
+ /* Mark this circuit "unusable for new streams". */
+ /* XXXX023 this is a kludgy way to do this. */
+ tor_assert(circ->_base.timestamp_dirty);
+ circ->_base.timestamp_dirty -= get_options()->MaxCircuitDirtiness;
return -1;
}
@@ -2191,7 +2377,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;
}
@@ -2199,7 +2385,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;
}
@@ -2209,12 +2395,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);
@@ -2246,7 +2426,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. */
@@ -2336,7 +2517,7 @@ tell_controller_about_resolved_result(edge_connection_t *conn,
* certain errors or for values that didn't come via DNS. <b>expires</b> is
* a time when the answer expires, or -1 or TIME_MAX if there's a good TTL.
**/
-/* XXXX022 the use of the ttl and expires fields is nutty. Let's make this
+/* XXXX023 the use of the ttl and expires fields is nutty. Let's make this
* interface and those that use it less ugly. */
void
connection_ap_handshake_socks_resolved(edge_connection_t *conn,
@@ -2512,6 +2693,7 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
char *address=NULL;
uint16_t port;
or_circuit_t *or_circ = NULL;
+ or_options_t *options = get_options();
assert_circuit_ok(circ);
if (!CIRCUIT_IS_ORIGIN(circ))
@@ -2526,7 +2708,7 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
* that we have a stream connected to a circuit, and we don't connect to a
* circuit until we have a pending/successful resolve. */
- if (!server_mode(get_options()) &&
+ if (!server_mode(options) &&
circ->purpose != CIRCUIT_PURPOSE_S_REND_JOINED) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"Relay begin cell at non-server. Closing.");
@@ -2560,21 +2742,30 @@ 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 && !options->AllowSingleHopExits &&
+ (or_circ->is_first_hop ||
+ (!connection_or_digest_is_known_relay(
+ or_circ->p_conn->identity_digest) &&
+ should_refuse_unknown_exits(options)))) {
/* 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.");
+ "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;
}
} else if (rh.command == RELAY_COMMAND_BEGIN_DIR) {
- if (!directory_permits_begindir_requests(get_options()) ||
+ if (!directory_permits_begindir_requests(options) ||
circ->purpose != CIRCUIT_PURPOSE_OR) {
relay_send_end_cell_from_edge(rh.stream_id, circ,
END_STREAM_REASON_NOTDIRECTORY, NULL);
@@ -2600,6 +2791,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;
@@ -2630,7 +2826,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;
@@ -2657,7 +2853,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);
}
@@ -2750,7 +2946,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);
@@ -2762,17 +2958,17 @@ connection_exit_connect(edge_connection_t *edge_conn)
log_debug(LD_EXIT,"about to try connecting");
switch (connection_connect(conn, conn->address, addr, port, &socket_error)) {
- case -1:
- /* XXX021 use socket_error below rather than trying to piece things
- * together from the current errno, which may have been clobbered. */
- connection_edge_end_errno(edge_conn);
+ case -1: {
+ int reason = errno_to_stream_end_reason(socket_error);
+ connection_edge_end(edge_conn, reason);
circuit_detach_stream(circuit_get_by_edge_conn(edge_conn), edge_conn);
connection_free(conn);
return;
+ }
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;
@@ -2785,7 +2981,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)) {
@@ -2832,13 +3028,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) {
@@ -2893,6 +3093,8 @@ connection_edge_is_rendezvous_stream(edge_connection_t *conn)
int
connection_ap_can_use_exit(edge_connection_t *conn, routerinfo_t *exit)
{
+ or_options_t *options = get_options();
+
tor_assert(conn);
tor_assert(conn->_base.type == CONN_TYPE_AP);
tor_assert(conn->socks_request);
@@ -2938,20 +3140,26 @@ 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 &&
+ routerset_contains_router(options->_ExcludeExitNodesUnion, exit)) {
+ /* Not a suitable exit. Refuse 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];
@@ -2960,8 +3168,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 */
@@ -2974,17 +3190,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");
-}
-