From e5885deab578188582052c6885ffe0b59cba6151 Mon Sep 17 00:00:00 2001 From: Roger Dingledine Date: Sun, 28 Oct 2007 08:16:19 +0000 Subject: [PATCH] Separate "SOCKS_COMMAND_CONNECT_DIR" into two flags in edge_connection_t: want_onehop if it must attach to a circuit with only one hop (e.g. for the current tunnelled connections that use begin_dir), and use_begindir if we mean to use a BEGIN_DIR relay command to establish the stream rather than the normal BEGIN. Now we can make anonymized begin_dir connections for (e.g.) more secure hidden service posting and fetching. svn:r12244 --- ChangeLog | 9 +++++++++ doc/spec/socks-extensions.txt | 2 ++ src/or/buffers.c | 2 -- src/or/circuituse.c | 36 ++++++++++++++++++----------------- src/or/connection_edge.c | 24 +++++++++++++---------- src/or/directory.c | 29 +++++++++++++--------------- src/or/or.h | 17 +++++++++-------- 7 files changed, 66 insertions(+), 53 deletions(-) diff --git a/ChangeLog b/ChangeLog index 062c55d925..fb19a3acd0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,13 @@ Changes in version 0.2.0.10-alpha - 2007-1?-?? + o Major features: + - Separate "SOCKS_COMMAND_CONNECT_DIR" into two flags in + edge_connection_t: want_onehop if it must attach to a circuit with + only one hop (e.g. for the current tunnelled connections that use + begin_dir), and use_begindir if we mean to use a BEGIN_DIR relay + command to establish the stream rather than the normal BEGIN. Now + we can make anonymized begin_dir connections for (e.g.) more secure + hidden service posting and fetching. + o Major bugfixes: - Stop servers from crashing if they set a Family option (or maybe in other situations too). Bugfix on 0.2.0.9-alpha; reported diff --git a/doc/spec/socks-extensions.txt b/doc/spec/socks-extensions.txt index 8097c66456..49c9660b1e 100644 --- a/doc/spec/socks-extensions.txt +++ b/doc/spec/socks-extensions.txt @@ -60,6 +60,8 @@ Tor's extensions to the SOCKS protocol directory port of the Tor server specified by address:port (the port specified should be the ORPort of the server). It uses a one-hop tunnel and a "BEGIN_DIR" relay cell to accomplish this secure connection. + Th F2 command value was removed in Tor 0.2.0.10-alpha in favor of a + new use_begindir flag in edge_connection_t. 4. HTTP-resistance diff --git a/src/or/buffers.c b/src/or/buffers.c index a225962b1d..d982330593 100644 --- a/src/or/buffers.c +++ b/src/or/buffers.c @@ -1197,7 +1197,6 @@ fetch_from_buf_socks(buf_t *buf, socks_request_t *req, return 0; /* not yet */ req->command = (unsigned char) *(buf->cur+1); if (req->command != SOCKS_COMMAND_CONNECT && - req->command != SOCKS_COMMAND_CONNECT_DIR && req->command != SOCKS_COMMAND_RESOLVE && req->command != SOCKS_COMMAND_RESOLVE_PTR) { /* not a connect or resolve or a resolve_ptr? we don't support it. */ @@ -1292,7 +1291,6 @@ fetch_from_buf_socks(buf_t *buf, socks_request_t *req, req->command = (unsigned char) *(buf->cur+1); if (req->command != SOCKS_COMMAND_CONNECT && - req->command != SOCKS_COMMAND_CONNECT_DIR && req->command != SOCKS_COMMAND_RESOLVE) { /* not a connect or resolve? we don't support it. (No resolve_ptr with * socks4.) */ diff --git a/src/or/circuituse.c b/src/or/circuituse.c index 1021cc1e43..ca1f4d333e 100644 --- a/src/or/circuituse.c +++ b/src/or/circuituse.c @@ -87,7 +87,7 @@ circuit_is_acceptable(circuit_t *circ, edge_connection_t *conn, * or is a rendezvous circuit. */ } if (build_state->onehop_tunnel) { - if (conn->socks_request->command != SOCKS_COMMAND_CONNECT_DIR) { + if (!conn->want_onehop) { log_debug(LD_CIRC,"Skipping one-hop circuit."); return 0; } @@ -100,7 +100,7 @@ circuit_is_acceptable(circuit_t *circ, edge_connection_t *conn, return 0; /* this is a circuit to somewhere else */ } } else { - if (conn->socks_request->command == SOCKS_COMMAND_CONNECT_DIR) { + if (conn->want_onehop) { /* don't use three-hop circuits -- that could hurt our anonymity. */ return 0; } @@ -835,6 +835,8 @@ circuit_launch_by_extend_info(uint8_t purpose, int onehop_tunnel, if ((extend_info || purpose != CIRCUIT_PURPOSE_C_GENERAL) && purpose != CIRCUIT_PURPOSE_TESTING && !onehop_tunnel) { /* see if there are appropriate circs available to cannibalize. */ + /* XXX020 if we're planning to add a hop, perhaps we want to look for + * internal circs rather than exit circs? -RD */ circ = circuit_find_to_cannibalize(purpose, extend_info, need_uptime, need_capacity, internal); if (circ) { @@ -948,11 +950,12 @@ circuit_get_open_circ_or_launch(edge_connection_t *conn, tor_assert(circp); tor_assert(conn->_base.state == AP_CONN_STATE_CIRCUIT_WAIT); check_exit_policy = - (conn->socks_request->command == SOCKS_COMMAND_CONNECT) && + conn->socks_request->command == SOCKS_COMMAND_CONNECT && + !conn->use_begindir && !connection_edge_is_rendezvous_stream(conn); - want_onehop = conn->socks_request->command == SOCKS_COMMAND_CONNECT_DIR; + want_onehop = conn->want_onehop; - need_uptime = (conn->socks_request->command == SOCKS_COMMAND_CONNECT) && + need_uptime = !conn->want_onehop && !conn->use_begindir && smartlist_string_num_isin(options->LongLivedPorts, conn->socks_request->port); need_internal = desired_circuit_purpose != CIRCUIT_PURPOSE_C_GENERAL; @@ -1005,6 +1008,8 @@ circuit_get_open_circ_or_launch(edge_connection_t *conn, /* is one already on the way? */ circ = circuit_get_best(conn, 0, desired_circuit_purpose, need_uptime, need_internal); + if (circ) + log_debug(LD_CIRC, "one on the way!"); if (!circ) { extend_info_t *extend_info=NULL; uint8_t new_circ_purpose; @@ -1221,17 +1226,14 @@ connection_ap_handshake_attach_chosen_circuit(edge_connection_t *conn, link_apconn_to_circ(conn, circ, cpath); tor_assert(conn->socks_request); - switch (conn->socks_request->command) { - case SOCKS_COMMAND_CONNECT: + if (conn->socks_request->command == SOCKS_COMMAND_CONNECT) { + if (!conn->use_begindir) consider_recording_trackhost(conn, circ); - /* fall through */ - case SOCKS_COMMAND_CONNECT_DIR: - if (connection_ap_handshake_send_begin(conn) < 0) - return -1; - break; - default: - if (connection_ap_handshake_send_resolve(conn) < 0) - return -1; + if (connection_ap_handshake_send_begin(conn) < 0) + return -1; + } else { + if (connection_ap_handshake_send_resolve(conn) < 0) + return -1; } return 1; @@ -1254,7 +1256,7 @@ connection_ap_handshake_attach_circuit(edge_connection_t *conn) tor_assert(conn); tor_assert(conn->_base.state == AP_CONN_STATE_CIRCUIT_WAIT); tor_assert(conn->socks_request); - want_onehop = conn->socks_request->command == SOCKS_COMMAND_CONNECT_DIR; + want_onehop = conn->want_onehop; conn_age = time(NULL) - conn->_base.timestamp_created; @@ -1307,7 +1309,7 @@ connection_ap_handshake_attach_circuit(edge_connection_t *conn) log_debug(LD_APP|LD_CIRC, "Attaching apconn to circ %d (stream %d sec old).", circ->_base.n_circ_id, conn_age); - /* here, print the circ's path. so people can figure out which circs are + /* print the circ's path, so people can figure out which circs are * sucking. */ circuit_log_path(LOG_INFO,LD_APP|LD_CIRC,circ); diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c index da78784d80..ba0d2a85a5 100644 --- a/src/or/connection_edge.c +++ b/src/or/connection_edge.c @@ -1379,7 +1379,7 @@ connection_ap_handshake_rewrite_and_attach(edge_connection_t *conn, return -1; } - if (!conn->chosen_exit_name && !circ) { + if (!conn->use_begindir && !conn->chosen_exit_name && !circ) { /* see if we can find a suitable enclave exit */ routerinfo_t *r = router_find_exact_exit_enclave(socks->address, socks->port); @@ -1395,11 +1395,12 @@ connection_ap_handshake_rewrite_and_attach(edge_connection_t *conn, } } - /* help predict this next time */ - rep_hist_note_used_port(socks->port, time(NULL)); + if (!conn->use_begindir) { + /* help predict this next time */ + rep_hist_note_used_port(socks->port, time(NULL)); + } } else if (socks->command == SOCKS_COMMAND_RESOLVE_PTR) { rep_hist_note_used_resolve(time(NULL)); /* help predict this next time */ - } else if (socks->command == SOCKS_COMMAND_CONNECT_DIR) { ; /* nothing */ } else { tor_fragile_assert(); @@ -1840,8 +1841,8 @@ connection_ap_handshake_send_begin(edge_connection_t *ap_conn) log_debug(LD_APP, "Sending relay cell to begin stream %d.", ap_conn->stream_id); - begin_type = ap_conn->socks_request->command == SOCKS_COMMAND_CONNECT ? - RELAY_COMMAND_BEGIN : RELAY_COMMAND_BEGIN_DIR; + begin_type = ap_conn->use_begindir ? + RELAY_COMMAND_BEGIN_DIR : RELAY_COMMAND_BEGIN; if (begin_type == RELAY_COMMAND_BEGIN) { tor_assert(circ->build_state->onehop_tunnel == 0); } @@ -1955,7 +1956,7 @@ connection_ap_handshake_send_resolve(edge_connection_t *ap_conn) */ edge_connection_t * connection_ap_make_link(char *address, uint16_t port, - const char *digest, int command) + const char *digest, int use_begindir, int want_onehop) { edge_connection_t *conn; @@ -1973,8 +1974,10 @@ connection_ap_make_link(char *address, uint16_t port, strlcpy(conn->socks_request->address, address, sizeof(conn->socks_request->address)); conn->socks_request->port = port; - conn->socks_request->command = command; - if (command == SOCKS_COMMAND_CONNECT_DIR) { + conn->socks_request->command = SOCKS_COMMAND_CONNECT; + conn->want_onehop = want_onehop; + conn->use_begindir = use_begindir; + if (use_begindir) { conn->chosen_exit_name = tor_malloc(HEX_DIGEST_LEN+2); conn->chosen_exit_name[0] = '$'; base16_encode(conn->chosen_exit_name+1,HEX_DIGEST_LEN+1, @@ -2622,7 +2625,8 @@ connection_ap_can_use_exit(edge_connection_t *conn, routerinfo_t *exit) } } - if (conn->socks_request->command == SOCKS_COMMAND_CONNECT) { + if (conn->socks_request->command == SOCKS_COMMAND_CONNECT && + !conn->use_begindir) { struct in_addr in; uint32_t addr = 0; addr_policy_result_t r; diff --git a/src/or/directory.c b/src/or/directory.c index fb27d71be4..131b0e710a 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -609,17 +609,17 @@ directory_initiate_command(const char *address, uint32_t addr, { dir_connection_t *conn; or_options_t *options = get_options(); - int want_to_tunnel = options->TunnelDirConns && supports_begindir && - !anonymized_connection && or_port && - fascist_firewall_allows_address_or(addr, or_port); + int use_begindir = options->TunnelDirConns && supports_begindir && or_port && + (anonymized_connection || + fascist_firewall_allows_address_or(addr, or_port)); tor_assert(address); tor_assert(addr); tor_assert(or_port || dir_port); tor_assert(digest); - log_debug(LD_DIR, "anonymized %d, want_to_tunnel %d.", - anonymized_connection, want_to_tunnel); + log_debug(LD_DIR, "anonymized %d, use_begindir %d.", + anonymized_connection, use_begindir); log_debug(LD_DIR, "Initiating %s", dir_conn_purpose_to_string(dir_purpose)); @@ -627,7 +627,7 @@ directory_initiate_command(const char *address, uint32_t addr, /* set up conn so it's got all the data we need to remember */ conn->_base.addr = addr; - conn->_base.port = want_to_tunnel ? or_port : dir_port; + conn->_base.port = use_begindir ? or_port : dir_port; conn->_base.address = tor_strdup(address); memcpy(conn->identity_digest, digest, DIGEST_LEN); @@ -637,11 +637,12 @@ directory_initiate_command(const char *address, uint32_t addr, /* give it an initial state */ conn->_base.state = DIR_CONN_STATE_CONNECTING; - if (!anonymized_connection && !want_to_tunnel) { - /* then we want to connect directly */ + /* decide whether we can learn our IP address from this conn */ + conn->dirconn_direct = !anonymized_connection; + + if (!anonymized_connection && !use_begindir) { + /* then we want to connect to dirport directly */ - /* XXX020 we should set dirconn_direct to 1 even if want_to_tunnel -RD */ - conn->dirconn_direct = 1; if (options->HttpProxy) { addr = options->HttpProxyAddr; dir_port = options->HttpProxyPort; @@ -665,19 +666,15 @@ directory_initiate_command(const char *address, uint32_t addr, /* writable indicates finish, readable indicates broken link, error indicates broken link in windowsland. */ } - } else { /* we want to connect via tor */ + } else { /* we want to connect via a tor connection */ edge_connection_t *linked_conn; /* make an AP connection * populate it and add it at the right state * hook up both sides */ - conn->dirconn_direct = 0; linked_conn = connection_ap_make_link(conn->_base.address, conn->_base.port, - digest, - anonymized_connection ? - SOCKS_COMMAND_CONNECT : - SOCKS_COMMAND_CONNECT_DIR); + digest, use_begindir, conn->dirconn_direct); if (!linked_conn) { log_warn(LD_NET,"Making tunnel to dirserver failed."); connection_mark_for_close(TO_CONN(conn)); diff --git a/src/or/or.h b/src/or/or.h index 344745d8e7..e151a678ca 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -910,6 +910,12 @@ typedef struct edge_connection_t { /** True iff this connection is for a dns request only. */ unsigned int is_dns_request : 1; + /** True iff this stream wants a one-hop circuit (e.g. for begin_dir). */ + int want_onehop:1; + /** True iff this stream should use a begin_dir connection (either via + * onehop or via a whole circuit). */ + int use_begindir:1; + /** If this is a DNSPort connection, this field holds the pending DNS * request that we're going to try to answer. */ struct evdns_server_request *dns_server_request; @@ -2212,13 +2218,7 @@ static INLINE void or_state_mark_dirty(or_state_t *state, time_t when) /** Please turn this IP address into an FQDN, privately. */ #define SOCKS_COMMAND_RESOLVE_PTR 0xF1 -/** Please open an encrypted direct TCP connection to the directory port - * of the Tor server specified by address:port. (In this case address:port - * specifies the ORPort of the server.) */ -#define SOCKS_COMMAND_CONNECT_DIR 0xF2 - -#define SOCKS_COMMAND_IS_CONNECT(c) ((c)==SOCKS_COMMAND_CONNECT || \ - (c)==SOCKS_COMMAND_CONNECT_DIR) +#define SOCKS_COMMAND_IS_CONNECT(c) ((c)==SOCKS_COMMAND_CONNECT) #define SOCKS_COMMAND_IS_RESOLVE(c) ((c)==SOCKS_COMMAND_RESOLVE || \ (c)==SOCKS_COMMAND_RESOLVE_PTR) @@ -2583,7 +2583,8 @@ int connection_ap_handshake_send_begin(edge_connection_t *ap_conn); int connection_ap_handshake_send_resolve(edge_connection_t *ap_conn); edge_connection_t *connection_ap_make_link(char *address, uint16_t port, - const char *digest, int command); + const char *digest, + int use_begindir, int want_onehop); void connection_ap_handshake_socks_reply(edge_connection_t *conn, char *reply, size_t replylen, int endreason);