diff options
author | Roger Dingledine <arma@torproject.org> | 2004-11-29 08:34:54 +0000 |
---|---|---|
committer | Roger Dingledine <arma@torproject.org> | 2004-11-29 08:34:54 +0000 |
commit | c1dc17e6e2f194d8c7078218be96cb96b9aaa6bd (patch) | |
tree | 12d5e4d5f40c8f5655e6a2e12ac558fa74c4edb6 /src/or | |
parent | 4effabd72d7151b2fe943f981c435467da9d33cf (diff) | |
download | tor-c1dc17e6e2f194d8c7078218be96cb96b9aaa6bd.tar tor-c1dc17e6e2f194d8c7078218be96cb96b9aaa6bd.tar.gz |
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
Diffstat (limited to 'src/or')
-rw-r--r-- | src/or/circuituse.c | 15 | ||||
-rw-r--r-- | src/or/connection.c | 1 | ||||
-rw-r--r-- | src/or/connection_edge.c | 87 | ||||
-rw-r--r-- | src/or/or.h | 7 | ||||
-rw-r--r-- | src/or/rendclient.c | 27 | ||||
-rw-r--r-- | src/or/test.c | 6 |
6 files changed, 103 insertions, 40 deletions
diff --git a/src/or/circuituse.c b/src/or/circuituse.c index 9ab165c6f..1c753ec54 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 add670ea3..4c893692a 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 883413292..2c2111251 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 fb24f44aa..19fed785f 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 d89c3ba7c..c4fe53fb7 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 d59609269..ac98b589f 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); |