diff options
author | Roger Dingledine <arma@torproject.org> | 2006-12-13 00:28:56 +0000 |
---|---|---|
committer | Roger Dingledine <arma@torproject.org> | 2006-12-13 00:28:56 +0000 |
commit | 0dbf725927c0b3a7f88b852b272573c91857be9b (patch) | |
tree | bea851e8726f18a8b463f950bfc1694ae6be6aa2 | |
parent | f5164ba61d8cf062bbc1beb2dfbca0abb3415e93 (diff) | |
download | tor-0dbf725927c0b3a7f88b852b272573c91857be9b.tar.gz tor-0dbf725927c0b3a7f88b852b272573c91857be9b.zip |
Infrastructure to test BEGIN_DIR cells.
New socks command CONNECT_DIR. New config option TunnelDirConns that
builds a circ ending at the directory server and delivers a BEGIN_DIR
cell if it's running 0.1.2.2-alpha or later. We still need to make
one-hop circs when appropriate, while making other conns avoid them.
svn:r9098
-rw-r--r-- | src/or/buffers.c | 2 | ||||
-rw-r--r-- | src/or/circuituse.c | 30 | ||||
-rw-r--r-- | src/or/config.c | 1 | ||||
-rw-r--r-- | src/or/connection_edge.c | 41 | ||||
-rw-r--r-- | src/or/control.c | 3 | ||||
-rw-r--r-- | src/or/directory.c | 35 | ||||
-rw-r--r-- | src/or/or.h | 13 | ||||
-rw-r--r-- | src/or/relay.c | 3 | ||||
-rw-r--r-- | src/or/router.c | 3 | ||||
-rw-r--r-- | src/or/routerparse.c | 2 |
10 files changed, 86 insertions, 47 deletions
diff --git a/src/or/buffers.c b/src/or/buffers.c index 154bfbbc8b..55120c60a7 100644 --- a/src/or/buffers.c +++ b/src/or/buffers.c @@ -974,6 +974,7 @@ 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. */ @@ -1065,6 +1066,7 @@ 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 dd56c4621a..d5f5fce265 100644 --- a/src/or/circuituse.c +++ b/src/or/circuituse.c @@ -902,16 +902,18 @@ circuit_get_open_circ_or_launch(edge_connection_t *conn, origin_circuit_t **circp) { origin_circuit_t *circ; - int is_resolve; + int check_exit_policy; int need_uptime, need_internal; tor_assert(conn); tor_assert(circp); tor_assert(conn->_base.state == AP_CONN_STATE_CIRCUIT_WAIT); - is_resolve = (conn->socks_request->command == SOCKS_COMMAND_RESOLVE || - conn->socks_request->command == SOCKS_COMMAND_RESOLVE_PTR); + check_exit_policy = + (conn->socks_request->command == SOCKS_COMMAND_CONNECT) && + !connection_edge_is_rendezvous_stream(conn); - need_uptime = smartlist_string_num_isin(get_options()->LongLivedPorts, + need_uptime = (conn->socks_request->command == SOCKS_COMMAND_CONNECT) && + smartlist_string_num_isin(get_options()->LongLivedPorts, conn->socks_request->port); need_internal = desired_circuit_purpose != CIRCUIT_PURPOSE_C_GENERAL; @@ -941,7 +943,7 @@ circuit_get_open_circ_or_launch(edge_connection_t *conn, } /* Do we need to check exit policy? */ - if (!is_resolve && !connection_edge_is_rendezvous_stream(conn)) { + if (check_exit_policy) { struct in_addr in; uint32_t addr = 0; if (tor_inet_aton(conn->socks_request->address, &in)) @@ -1125,13 +1127,17 @@ connection_ap_handshake_attach_chosen_circuit(edge_connection_t *conn, link_apconn_to_circ(conn, circ); tor_assert(conn->socks_request); - if (conn->socks_request->command == SOCKS_COMMAND_CONNECT) { - consider_recording_trackhost(conn, circ); - if (connection_ap_handshake_send_begin(conn, circ)<0) - return -1; - } else { - if (connection_ap_handshake_send_resolve(conn, circ)<0) - return -1; + switch (conn->socks_request->command) { + case SOCKS_COMMAND_CONNECT: + consider_recording_trackhost(conn, circ); + /* fall through */ + case SOCKS_COMMAND_CONNECT_DIR: + if (connection_ap_handshake_send_begin(conn, circ)<0) + return -1; + break; + default: + if (connection_ap_handshake_send_resolve(conn, circ)<0) + return -1; } return 1; diff --git a/src/or/config.c b/src/or/config.c index 8823dae43f..cc78bcb008 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -247,6 +247,7 @@ static config_var_t _option_vars[] = { OBSOLETE("TrafficShaping"), VAR("TransListenAddress", LINELIST, TransListenAddress, NULL), VAR("TransPort", UINT, TransPort, "0"), + VAR("TunnelDirConns", BOOL, TunnelDirConns, "0"), VAR("UseEntryGuards", BOOL, UseEntryGuards, "1"), VAR("User", STRING, User, NULL), VAR("V1AuthoritativeDirectory",BOOL, V1AuthoritativeDir, "0"), diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c index 9379d04a76..7e6d23aeac 100644 --- a/src/or/connection_edge.c +++ b/src/or/connection_edge.c @@ -55,7 +55,7 @@ _connection_mark_unattached_ap(edge_connection_t *conn, int endreason, "Bug: stream (marked at %s:%d) sending two socks replies?", file, line); - if (conn->socks_request->command == SOCKS_COMMAND_CONNECT) + if (SOCKS_COMMAND_IS_CONNECT(conn->socks_request->command)) connection_ap_handshake_socks_reply(conn, NULL, 0, endreason); else connection_ap_handshake_socks_resolved(conn, RESOLVED_TYPE_ERROR, @@ -1213,6 +1213,8 @@ connection_ap_handshake_rewrite_and_attach(edge_connection_t *conn, // XXXX NM Do anything here? 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(); } @@ -1230,7 +1232,7 @@ connection_ap_handshake_rewrite_and_attach(edge_connection_t *conn, rend_cache_entry_t *entry; int r; - if (socks->command != SOCKS_COMMAND_CONNECT) { + if (!SOCKS_COMMAND_IS_CONNECT(socks->command)) { /* if it's a resolve request, fail it right now, rather than * building all the circuits and then realizing it won't work. */ log_warn(LD_APP, @@ -1450,7 +1452,7 @@ connection_ap_handshake_process_socks(edge_connection_t *conn) return -1; } - if (socks->command == SOCKS_COMMAND_CONNECT) + 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); @@ -1546,7 +1548,7 @@ connection_ap_process_natd(edge_connection_t *conn) if (strcmpstart(tmp_buf, "[DEST ")) { log_warn(LD_APP,"Natd handshake was ill-formed; closing. The client " - "said: '%s'", + "said: %s", escaped(tmp_buf)); connection_mark_unattached_ap(conn, END_STREAM_REASON_INVALID_NATD_DEST); return -1; @@ -1564,7 +1566,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; @@ -1620,10 +1622,12 @@ connection_ap_handshake_send_begin(edge_connection_t *ap_conn, { char payload[CELL_PAYLOAD_SIZE]; int payload_len; + int begin_type; tor_assert(ap_conn->_base.type == CONN_TYPE_AP); tor_assert(ap_conn->_base.state == AP_CONN_STATE_CIRCUIT_WAIT); tor_assert(ap_conn->socks_request); + tor_assert(SOCKS_COMMAND_IS_CONNECT(ap_conn->socks_request->command)); ap_conn->stream_id = get_unique_stream_id_by_circ(circ); if (ap_conn->stream_id==0) { @@ -1641,9 +1645,11 @@ 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; + if (connection_edge_send_command(ap_conn, TO_CIRCUIT(circ), - RELAY_COMMAND_BEGIN, - payload, payload_len, + begin_type, payload, payload_len, ap_conn->cpath_layer) < 0) return -1; /* circuit is closed, don't continue */ @@ -1669,15 +1675,14 @@ connection_ap_handshake_send_resolve(edge_connection_t *ap_conn, const char *string_addr; char inaddr_buf[32]; - command = ap_conn->socks_request->command; - tor_assert(ap_conn->_base.type == CONN_TYPE_AP); tor_assert(ap_conn->_base.state == AP_CONN_STATE_CIRCUIT_WAIT); tor_assert(ap_conn->socks_request); - tor_assert(command == SOCKS_COMMAND_RESOLVE || - command == SOCKS_COMMAND_RESOLVE_PTR); tor_assert(circ->_base.purpose == CIRCUIT_PURPOSE_C_GENERAL); + command = ap_conn->socks_request->command; + tor_assert(SOCKS_COMMAND_IS_RESOLVE(command)); + ap_conn->stream_id = get_unique_stream_id_by_circ(circ); if (ap_conn->stream_id==0) { connection_mark_unattached_ap(ap_conn, END_STREAM_REASON_INTERNAL); @@ -1729,7 +1734,8 @@ connection_ap_handshake_send_resolve(edge_connection_t *ap_conn, * Return the other end of the socketpair, or -1 if error. */ int -connection_ap_make_bridge(char *address, uint16_t port) +connection_ap_make_bridge(char *address, uint16_t port, + const char *digest, int command) { int fd[2]; edge_connection_t *conn; @@ -1761,7 +1767,13 @@ connection_ap_make_bridge(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 = SOCKS_COMMAND_CONNECT; + conn->socks_request->command = command; + if (command == SOCKS_COMMAND_CONNECT_DIR) { + 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, + digest, DIGEST_LEN); + } conn->_base.address = tor_strdup("(local bridge)"); conn->_base.addr = 0; @@ -2396,8 +2408,7 @@ connection_ap_can_use_exit(edge_connection_t *conn, routerinfo_t *exit) exit->exit_policy); if (r == ADDR_POLICY_REJECTED || r == ADDR_POLICY_PROBABLY_REJECTED) return 0; - } else { /* Some kind of a resolve. */ - + } else if (SOCKS_COMMAND_IS_RESOLVE(conn->socks_request->command)) { /* Can't support reverse lookups without eventdns. */ if (conn->socks_request->command == SOCKS_COMMAND_RESOLVE_PTR && exit->has_old_dnsworkers) diff --git a/src/or/control.c b/src/or/control.c index 0b9502359a..9672a8ed66 100644 --- a/src/or/control.c +++ b/src/or/control.c @@ -1619,8 +1619,7 @@ getinfo_helper_events(control_connection_t *control_conn, case AP_CONN_STATE_CONTROLLER_WAIT: case AP_CONN_STATE_CIRCUIT_WAIT: if (conn->socks_request && - (conn->socks_request->command == SOCKS_COMMAND_RESOLVE || - conn->socks_request->command == SOCKS_COMMAND_RESOLVE_PTR)) + SOCKS_COMMAND_IS_RESOLVE(conn->socks_request->command)) state = "NEWRESOLVE"; else state = "NEW"; diff --git a/src/or/directory.c b/src/or/directory.c index 6d52e7029d..34fbf5b7ff 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -39,7 +39,7 @@ directory_initiate_command(const char *address, uint32_t addr, uint16_t port, static void directory_send_command(dir_connection_t *conn, const char *platform, - int purpose, const char *resource, + int purpose, int direct, const char *resource, const char *payload, size_t payload_len); static int directory_handle_command(dir_connection_t *conn); static int body_is_plausible(const char *body, size_t body_len, int purpose); @@ -370,12 +370,18 @@ directory_initiate_command(const char *address, uint32_t addr, const char *payload, size_t payload_len) { dir_connection_t *conn; + or_options_t *options = get_options(); + int want_to_tunnel = options->TunnelDirConns && platform && + tor_version_as_new_as(platform, "0.1.2.2-alpha"); tor_assert(address); tor_assert(addr); tor_assert(dir_port); tor_assert(digest); + log_debug(LD_DIR, "private %d, want_to_tunnel %d.", + private_connection, want_to_tunnel); + switch (purpose) { case DIR_PURPOSE_FETCH_DIR: log_debug(LD_DIR,"initiating directory fetch"); @@ -415,14 +421,14 @@ directory_initiate_command(const char *address, uint32_t addr, /* give it an initial state */ conn->_base.state = DIR_CONN_STATE_CONNECTING; - conn->dirconn_direct = (private_connection == 0); - if (!private_connection) { + if (!private_connection && !want_to_tunnel) { /* then we want to connect directly */ - if (get_options()->HttpProxy) { - addr = get_options()->HttpProxyAddr; - dir_port = get_options()->HttpProxyPort; + conn->dirconn_direct = 1; + if (options->HttpProxy) { + addr = options->HttpProxyAddr; + dir_port = options->HttpProxyPort; } switch (connection_connect(TO_CONN(conn), conn->_base.address, addr, @@ -437,7 +443,7 @@ directory_initiate_command(const char *address, uint32_t addr, /* fall through */ case 0: /* queue the command on the outbuf */ - directory_send_command(conn, platform, purpose, resource, + directory_send_command(conn, platform, purpose, 1, resource, payload, payload_len); connection_watch_events(TO_CONN(conn), EV_READ | EV_WRITE); /* writable indicates finish, readable indicates broken link, @@ -448,8 +454,13 @@ directory_initiate_command(const char *address, uint32_t addr, * populate it and add it at the right state * socketpair and hook up both sides */ - conn->_base.s = connection_ap_make_bridge(conn->_base.address, - conn->_base.port); + conn->dirconn_direct = 0; + conn->_base.s = + connection_ap_make_bridge(conn->_base.address, conn->_base.port, + digest, + private_connection ? + SOCKS_COMMAND_CONNECT : + SOCKS_COMMAND_CONNECT_DIR); if (conn->_base.s < 0) { log_warn(LD_NET,"Making AP bridge to dirserver failed."); connection_mark_for_close(TO_CONN(conn)); @@ -463,7 +474,7 @@ directory_initiate_command(const char *address, uint32_t addr, } conn->_base.state = DIR_CONN_STATE_CLIENT_SENDING; /* queue the command on the outbuf */ - directory_send_command(conn, platform, purpose, resource, + directory_send_command(conn, platform, purpose, 0, resource, payload, payload_len); connection_watch_events(TO_CONN(conn), EV_READ | EV_WRITE); } @@ -474,7 +485,7 @@ directory_initiate_command(const char *address, uint32_t addr, */ static void directory_send_command(dir_connection_t *conn, const char *platform, - int purpose, const char *resource, + int purpose, int direct, const char *resource, const char *payload, size_t payload_len) { char proxystring[256]; @@ -501,7 +512,7 @@ directory_send_command(dir_connection_t *conn, const char *platform, } /* come up with some proxy lines, if we're using one. */ - if (get_options()->HttpProxy) { + if (direct && get_options()->HttpProxy) { char *base64_authenticator=NULL; const char *authenticator = get_options()->HttpProxyAuthenticator; diff --git a/src/or/or.h b/src/or/or.h index 30a9992cf5..c6bcc18bc2 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -1648,8 +1648,10 @@ typedef struct { char *ServerDNSResolvConfFile; /**< If provided, we configure our internal * resolver from the file here rather than from * /etc/resolv.conf (Unix) or the registry (Windows). */ - int EnforceDistinctSubnets; /** If true, don't allow multiple routers in the + int EnforceDistinctSubnets; /**< If true, don't allow multiple routers in the * same network zone in the same circuit. */ + int TunnelDirConns; /**< If true, use BEGIN_DIR rather than BEGIN when + * possible. */ } or_options_t; /** Persistent state for an onion router, as saved to disk. */ @@ -1705,17 +1707,21 @@ static INLINE void or_state_mark_dirty(or_state_t *state, time_t when) #define MAX_SOCKS_REPLY_LEN 1024 #define MAX_SOCKS_ADDR_LEN 256 + #define SOCKS_COMMAND_CONNECT 0x01 +#define SOCKS_COMMAND_CONNECT_DIR 0xE0 #define SOCKS_COMMAND_RESOLVE 0xF0 #define SOCKS_COMMAND_RESOLVE_PTR 0xF1 +#define SOCKS_COMMAND_IS_CONNECT(c) ((c)==SOCKS_COMMAND_CONNECT || \ + (c)==SOCKS_COMMAND_CONNECT_DIR) #define SOCKS_COMMAND_IS_RESOLVE(c) ((c)==SOCKS_COMMAND_RESOLVE || \ (c)==SOCKS_COMMAND_RESOLVE_PTR) /** State of a SOCKS request from a user to an OP */ struct socks_request_t { char socks_version; /**< Which version of SOCKS did the client use? */ - int command; /**< What has the user requested? One of CONNECT or RESOLVE. */ + int command; /**< What has the user requested? One from the above list. */ size_t replylen; /**< Length of <b>reply</b>. */ char reply[MAX_SOCKS_REPLY_LEN]; /**< Write an entry into this string if * we want to specify our own socks reply, @@ -2017,7 +2023,8 @@ int connection_ap_handshake_send_begin(edge_connection_t *ap_conn, int connection_ap_handshake_send_resolve(edge_connection_t *ap_conn, origin_circuit_t *circ); -int connection_ap_make_bridge(char *address, uint16_t port); +int connection_ap_make_bridge(char *address, uint16_t port, + const char *digest, int command); void connection_ap_handshake_socks_reply(edge_connection_t *conn, char *reply, size_t replylen, int endreason); diff --git a/src/or/relay.c b/src/or/relay.c index 0923797077..3c5c8e1140 100644 --- a/src/or/relay.c +++ b/src/or/relay.c @@ -900,8 +900,7 @@ connection_edge_process_relay_cell_not_open( "not in state resolve_wait. Dropping."); return 0; } - tor_assert(conn->socks_request->command == SOCKS_COMMAND_RESOLVE || - conn->socks_request->command == SOCKS_COMMAND_RESOLVE_PTR); + tor_assert(SOCKS_COMMAND_IS_RESOLVE(conn->socks_request->command)); answer_len = cell->payload[RELAY_HEADER_SIZE+1]; if (rh->length < 2 || answer_len+2>rh->length) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, diff --git a/src/or/router.c b/src/or/router.c index 66f1f672ca..bc38f107cd 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -1015,7 +1015,8 @@ router_new_address_suggestion(const char *suggestion) /* first, learn what the IP address actually is */ if (!tor_inet_aton(suggestion, &in)) { - log_debug(LD_DIR, "Malformed X-Your-Address-Is header. Ignoring."); + log_debug(LD_DIR, "Malformed X-Your-Address-Is header %s. Ignoring.", + escaped(suggestion)); return; } addr = ntohl(in.s_addr); diff --git a/src/or/routerparse.c b/src/or/routerparse.c index 2c3e0d84be..874925d1a6 100644 --- a/src/or/routerparse.c +++ b/src/or/routerparse.c @@ -1821,6 +1821,8 @@ tor_version_as_new_as(const char *platform, const char *cutoff) char *s, *start; char tmp[128]; + tor_assert(platform); + if (tor_version_parse(cutoff, &cutoff_version)<0) { log_warn(LD_DIR,"Bug: cutoff version '%s' unparseable.",cutoff); return 0; |