summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoger Dingledine <arma@torproject.org>2004-11-29 08:34:54 +0000
committerRoger Dingledine <arma@torproject.org>2004-11-29 08:34:54 +0000
commitc1dc17e6e2f194d8c7078218be96cb96b9aaa6bd (patch)
tree12d5e4d5f40c8f5655e6a2e12ac558fa74c4edb6
parent4effabd72d7151b2fe943f981c435467da9d33cf (diff)
downloadtor-c1dc17e6e2f194d8c7078218be96cb96b9aaa6bd.tar.gz
tor-c1dc17e6e2f194d8c7078218be96cb96b9aaa6bd.zip
put in initial support for ".nickname.exit" addresses, to let alice
decide what exit node to use; based on a patch by geoff goodell. needs more work: e.g. it goes bananas building new circuits when the chosen exit node's exit policy rejects the connection. svn:r3015
-rw-r--r--src/or/circuituse.c15
-rw-r--r--src/or/connection.c1
-rw-r--r--src/or/connection_edge.c87
-rw-r--r--src/or/or.h7
-rw-r--r--src/or/rendclient.c27
-rw-r--r--src/or/test.c6
6 files changed, 103 insertions, 40 deletions
diff --git a/src/or/circuituse.c b/src/or/circuituse.c
index 9ab165c6f6..1c753ec54a 100644
--- a/src/or/circuituse.c
+++ b/src/or/circuituse.c
@@ -706,12 +706,27 @@ circuit_get_open_circ_or_launch(connection_t *conn,
}
if (!router_get_by_nickname(exitname)) {
log_fn(LOG_WARN,"Advertised intro point '%s' is not known. Closing.", exitname);
+ tor_free(exitname);
return -1;
}
/* XXX if we failed, then refetch the descriptor */
log_fn(LOG_INFO,"Chose %s as intro point for %s.", exitname, conn->rend_query);
}
+ /* If we have specified a particular exit node for our
+ * connection, then be sure to open a circuit to that exit node.
+ */
+ if(desired_circuit_purpose == CIRCUIT_PURPOSE_C_GENERAL) {
+ if (conn->chosen_exit_name) {
+ exitname = tor_strdup(conn->chosen_exit_name);
+ if(!router_get_by_nickname(exitname)) {
+ log_fn(LOG_WARN,"Requested exit point '%s' is not known. Closing.", exitname);
+ tor_free(exitname);
+ return -1;
+ }
+ }
+ }
+
if (desired_circuit_purpose == CIRCUIT_PURPOSE_C_REND_JOINED)
new_circ_purpose = CIRCUIT_PURPOSE_C_ESTABLISH_REND;
else if (desired_circuit_purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT)
diff --git a/src/or/connection.c b/src/or/connection.c
index add670ea30..4c893692a7 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -148,6 +148,7 @@ void connection_free(connection_t *conn) {
buf_free(conn->outbuf);
}
tor_free(conn->address);
+ tor_free(conn->chosen_exit_name);
if (connection_speaks_cells(conn)) {
if (conn->state == OR_CONN_STATE_OPEN)
diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c
index 8834132929..2c2111251b 100644
--- a/src/or/connection_edge.c
+++ b/src/or/connection_edge.c
@@ -352,6 +352,7 @@ void connection_ap_attach_pending(void)
static int connection_ap_handshake_process_socks(connection_t *conn) {
socks_request_t *socks;
int sockshere;
+ int addresstype;
tor_assert(conn);
tor_assert(conn->type == CONN_TYPE_AP);
@@ -397,9 +398,24 @@ static int connection_ap_handshake_process_socks(connection_t *conn) {
}
}
- /* this call _modifies_ socks->address iff it's a hidden-service request */
- if (rend_parse_rendezvous_address(socks->address) < 0) {
- /* normal request */
+ /* Parse the address provided by SOCKS. Modify it in-place if it
+ * specifies a hidden-service (.onion) or particular exit node (.exit).
+ */
+ addresstype = parse_address(socks->address);
+
+ if (addresstype == 1) {
+ /* .exit -- modify conn to specify the exit node. */
+ char *s = strrchr(socks->address,'.');
+ if (!s || s[1] == '\0') {
+ log_fn(LOG_WARN,"Malformed address '%s.exit'. Refusing.", socks->address);
+ return -1;
+ }
+ conn->chosen_exit_name = tor_strdup(s+1);
+ *s = 0;
+ }
+
+ if (addresstype != 2) {
+ /* not a hidden-service request (i.e. normal or .exit) */
if (socks->command == SOCKS_COMMAND_CONNECT && socks->port == 0) {
log_fn(LOG_WARN,"Application asked to connect to port 0. Refusing.");
return -1;
@@ -447,7 +463,7 @@ static int connection_ap_handshake_process_socks(connection_t *conn) {
}
}
}
- return 0;
+ return 0; /* unreached but keeps the compiler happy */
}
/** Iterate over the two bytes of stream_id until we get one that is not
@@ -991,18 +1007,34 @@ int connection_ap_can_use_exit(connection_t *conn, routerinfo_t *exit)
tor_assert(conn);
tor_assert(conn->type == CONN_TYPE_AP);
tor_assert(conn->socks_request);
+ tor_assert(exit);
log_fn(LOG_DEBUG,"considering nickname %s, for address %s / port %d:",
exit->nickname, conn->socks_request->address,
conn->socks_request->port);
+
+ /* If a particular exit node has been requested for the new connection,
+ * make sure the exit node of the existing circuit matches exactly.
+ */
+ if (conn->chosen_exit_name) {
+ if (router_get_by_nickname(conn->chosen_exit_name) != exit) {
+ /* doesn't match */
+ log_fn(LOG_DEBUG,"Requested node '%s', considering node '%s'. No.",
+ conn->chosen_exit_name, exit->nickname);
+ return 0;
+ }
+ }
+
if (conn->socks_request->command == SOCKS_COMMAND_RESOLVE) {
/* 0.0.8 servers have buggy resolve support. */
- return tor_version_as_new_as(exit->platform, "0.0.9pre1");
+ if (!tor_version_as_new_as(exit->platform, "0.0.9pre1"))
+ return 0;
+ } else {
+ addr = client_dns_lookup_entry(conn->socks_request->address);
+ if (router_compare_addr_to_addr_policy(addr, conn->socks_request->port,
+ exit->exit_policy) < 0)
+ return 0;
}
- addr = client_dns_lookup_entry(conn->socks_request->address);
- if (router_compare_addr_to_addr_policy(addr, conn->socks_request->port,
- exit->exit_policy) < 0)
- return 0;
return 1;
}
@@ -1211,3 +1243,40 @@ set_exit_redirects(smartlist_t *lst)
redirect_exit_list = lst;
}
+/** If address is of the form "y.onion" with a well-formed handle y:
+ * Put a '\0' after y, lower-case it, and return 2.
+ *
+ * If address is of the form "y.exit":
+ * Put a '\0' after y and return 1.
+ *
+ * Otherwise:
+ * Return 0 and change nothing.
+ */
+int parse_address(char *address) {
+ char *s;
+ char query[REND_SERVICE_ID_LEN+1];
+
+ s = strrchr(address,'.');
+ if (!s) return 0; /* no dot, thus normal */
+ if (!strcasecmp(s+1,"exit")) {
+ *s = 0; /* null-terminate it */
+ return 1; /* .exit */
+ }
+ if (strcasecmp(s+1,"onion"))
+ return 0; /* neither .exit nor .onion, thus normal */
+
+ /* so it is .onion */
+ *s = 0; /* null-terminate it */
+ if (strlcpy(query, address, REND_SERVICE_ID_LEN+1) >= REND_SERVICE_ID_LEN+1)
+ goto failed;
+ tor_strlower(query);
+ if (rend_valid_service_id(query)) {
+ tor_strlower(address);
+ return 2; /* success */
+ }
+failed:
+ /* otherwise, return to previous state and return 0 */
+ *s = '.';
+ return 0;
+}
+
diff --git a/src/or/or.h b/src/or/or.h
index fb24f44aa3..19fed785ff 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -526,6 +526,9 @@ struct connection_t {
char identity_digest[DIGEST_LEN]; /**< Hash of identity_pkey */
char *nickname; /**< Nickname of OR on other side (if any). */
+ /** Nickname of planned exit node -- to be used with .exit support. */
+ char *chosen_exit_name;
+
/* Used only by OR connections: */
tor_tls *tls; /**< TLS connection state (OR only.) */
uint16_t next_circ_id; /**< Which circ_id do we try to use next on
@@ -1223,6 +1226,7 @@ int connection_ap_can_use_exit(connection_t *conn, routerinfo_t *exit);
void connection_ap_expire_beginning(void);
void connection_ap_attach_pending(void);
+void parse_socks_policy(void);
int socks_policy_permits_address(uint32_t addr);
void client_dns_init(void);
@@ -1231,7 +1235,7 @@ int client_dns_incr_failures(const char *address);
void client_dns_set_entry(const char *address, uint32_t val);
void client_dns_clean(void);
void set_exit_redirects(smartlist_t *lst);
-void parse_socks_policy(void);
+int parse_address(char *address);
/********************************* connection_or.c ***************************/
@@ -1453,7 +1457,6 @@ int rend_client_receive_rendezvous(circuit_t *circ, const char *request, size_t
void rend_client_desc_fetched(char *query, int status);
char *rend_client_get_random_intro(char *query);
-int rend_parse_rendezvous_address(char *address);
int rend_client_send_introduction(circuit_t *introcirc, circuit_t *rendcirc);
diff --git a/src/or/rendclient.c b/src/or/rendclient.c
index d89c3ba7c5..c4fe53fb7f 100644
--- a/src/or/rendclient.c
+++ b/src/or/rendclient.c
@@ -439,30 +439,3 @@ char *rend_client_get_random_intro(char *query) {
return nickname;
}
-/** If address is of the form "y.onion" with a well-formed handle y,
- * then put a '\0' after y, lower-case it, and return 0.
- * Else return -1 and change nothing.
- */
-int rend_parse_rendezvous_address(char *address) {
- char *s;
- char query[REND_SERVICE_ID_LEN+1];
-
- s = strrchr(address,'.');
- if (!s) return -1; /* no dot */
- if (strcasecmp(s+1,"onion"))
- return -1; /* not .onion */
-
- *s = 0; /* null terminate it */
- if (strlcpy(query, address, REND_SERVICE_ID_LEN+1) >= REND_SERVICE_ID_LEN+1)
- goto failed;
- tor_strlower(query);
- if (rend_valid_service_id(query)) {
- tor_strlower(address);
- return 0; /* success */
- }
-failed:
- /* otherwise, return to previous state and return -1 */
- *s = '.';
- return -1;
-}
-
diff --git a/src/or/test.c b/src/or/test.c
index d596092691..ac98b589f9 100644
--- a/src/or/test.c
+++ b/src/or/test.c
@@ -1182,6 +1182,7 @@ test_rend_fns(void)
{
char address1[] = "fooaddress.onion";
char address2[] = "aaaaaaaaaaaaaaaa.onion";
+ char address3[] = "fooaddress.exit";
rend_service_descriptor_t *d1, *d2;
char *encoded;
size_t len;
@@ -1210,8 +1211,9 @@ test_rend_fns(void)
test_streq(d2->intro_points[1], "crow");
test_streq(d2->intro_points[2], "joel");
- test_eq(-1, rend_parse_rendezvous_address(address1));
- test_eq( 0, rend_parse_rendezvous_address(address2));
+ test_eq(0, parse_address(address1));
+ test_eq(2, parse_address(address2));
+ test_eq(1, parse_address(address3));
rend_service_descriptor_free(d1);
rend_service_descriptor_free(d2);