diff options
Diffstat (limited to 'src/or/connection_edge.c')
-rw-r--r-- | src/or/connection_edge.c | 87 |
1 files changed, 78 insertions, 9 deletions
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; +} + |