From 7a79acd9f6d377533940ee12fcb3afaaa982b04d Mon Sep 17 00:00:00 2001 From: Roger Dingledine Date: Sun, 27 Mar 2005 06:37:56 +0000 Subject: [PATCH] clean up socks reply stuff more. add a few more reasons so we can be more informative. svn:r3895 --- src/or/connection_edge.c | 41 +++++++++++++++++++++++++++++++--------- src/or/control.c | 2 +- src/or/main.c | 3 +-- src/or/or.h | 8 ++++++++ src/or/relay.c | 13 ++++++++++--- src/or/rendclient.c | 2 +- 6 files changed, 53 insertions(+), 16 deletions(-) diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c index ad74adfb07..2636ac0a5d 100644 --- a/src/or/connection_edge.c +++ b/src/or/connection_edge.c @@ -26,16 +26,24 @@ static int address_is_in_virtual_range(const char *addr); */ void connection_close_unattached_ap(connection_t *conn, int endreason) { + tor_assert(conn->type == CONN_TYPE_AP); conn->has_sent_end = 1; /* no circ yet */ + if (!conn->socks_request->has_finished) { socks5_reply_status_t socksreason = connection_edge_end_reason_socks5_response(endreason); + + if (endreason == END_STREAM_REASON_ALREADY_SOCKS_REPLIED) + log_fn(LOG_WARN,"Bug: stream (marked at %s:%d) sending two socks replies?", + conn->marked_for_close_file, conn->marked_for_close); + if (conn->socks_request->command == SOCKS_COMMAND_CONNECT) connection_ap_handshake_socks_reply(conn, NULL, 0, socksreason); else connection_ap_handshake_socks_resolved(conn,RESOLVED_TYPE_ERROR,0,NULL); } + connection_mark_for_close(conn); conn->hold_open_until_flushed = 1; } @@ -90,7 +98,7 @@ int connection_edge_process_inbuf(connection_t *conn, int package_partial) { switch (conn->state) { case AP_CONN_STATE_SOCKS_WAIT: if (connection_ap_handshake_process_socks(conn) < 0) { - connection_close_unattached_ap(conn, END_STREAM_REASON_TIMEOUT); + /* already marked */ return -1; } return 0; @@ -345,7 +353,7 @@ void connection_ap_expire_beginning(void) { conn->timestamp_lastread += 15; /* move it back into 'pending' state, and try to attach. */ if (connection_ap_detach_retriable(conn, circ)<0) { - connection_close_unattached_ap(conn, END_STREAM_REASON_MISC); + connection_close_unattached_ap(conn, END_STREAM_REASON_CANT_ATTACH); } } /* end for */ } @@ -368,7 +376,7 @@ void connection_ap_attach_pending(void) conn->state != AP_CONN_STATE_CIRCUIT_WAIT) continue; if (connection_ap_handshake_attach_circuit(conn) < 0) { - connection_close_unattached_ap(conn, END_STREAM_REASON_MISC); + connection_close_unattached_ap(conn, END_STREAM_REASON_CANT_ATTACH); } } } @@ -865,12 +873,12 @@ static int connection_ap_handshake_process_socks(connection_t *conn) { log_fn(LOG_DEBUG,"reply is already set for us. Using it."); connection_ap_handshake_socks_reply(conn, socks->reply, socks->replylen, SOCKS5_GENERAL_ERROR); - socks->replylen = 0; /* zero it out so we can do another round of negotiation */ } else { log_fn(LOG_WARN,"Fetching socks handshake failed. Closing."); connection_ap_handshake_socks_reply(conn, NULL, 0, SOCKS5_GENERAL_ERROR); } - return sockshere; + connection_close_unattached_ap(conn, END_STREAM_REASON_ALREADY_SOCKS_REPLIED); + return -1; } /* else socks handshake is done, continue processing */ tor_strlower(socks->address); /* normalize it */ @@ -886,6 +894,7 @@ static int connection_ap_handshake_process_socks(connection_t *conn) { */ log_fn(LOG_WARN,"Missing mapping for virtual address '%s'. Refusing.", socks->address); + connection_close_unattached_ap(conn, END_STREAM_REASON_INTERNAL); return -1; } @@ -899,6 +908,7 @@ static int connection_ap_handshake_process_socks(connection_t *conn) { char *s = strrchr(socks->address,'.'); if (!s || s[1] == '\0') { log_fn(LOG_WARN,"Malformed exit address '%s'. Refusing.", socks->address); + connection_close_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL); return -1; } conn->chosen_exit_name = tor_strdup(s+1); @@ -910,6 +920,7 @@ static int connection_ap_handshake_process_socks(connection_t *conn) { if (address_is_invalid_destination(socks->address)) { log_fn(LOG_WARN,"Destination '%s' seems to be an invalid hostname. Failing.", socks->address); + connection_close_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL); return -1; } @@ -920,13 +931,14 @@ static int connection_ap_handshake_process_socks(connection_t *conn) { if (strlen(socks->address) > RELAY_PAYLOAD_SIZE) { log_fn(LOG_WARN,"Address to be resolved is too large. Failing."); connection_ap_handshake_socks_resolved(conn,RESOLVED_TYPE_ERROR,0,NULL); + connection_close_unattached_ap(conn, END_STREAM_REASON_ALREADY_SOCKS_REPLIED); return -1; } if (tor_inet_aton(socks->address, &in)) { /* see if it's an IP already */ answer = in.s_addr; connection_ap_handshake_socks_resolved(conn,RESOLVED_TYPE_IPV4,4, (char*)&answer); - connection_close_unattached_ap(conn, END_STREAM_REASON_DONE); + connection_close_unattached_ap(conn, END_STREAM_REASON_ALREADY_SOCKS_REPLIED); return 0; } rep_hist_note_used_resolve(time(NULL)); /* help predict this next time */ @@ -934,6 +946,7 @@ static int connection_ap_handshake_process_socks(connection_t *conn) { } else { /* socks->command == SOCKS_COMMAND_CONNECT */ if (socks->port == 0) { log_fn(LOG_NOTICE,"Application asked to connect to port 0. Refusing."); + connection_close_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL); return -1; } rep_hist_note_used_port(socks->port, time(NULL)); /* help predict this next time */ @@ -941,7 +954,11 @@ static int connection_ap_handshake_process_socks(connection_t *conn) { } if (! get_options()->LeaveStreamsUnattached) { conn->state = AP_CONN_STATE_CIRCUIT_WAIT; - return connection_ap_handshake_attach_circuit(conn); + if (connection_ap_handshake_attach_circuit(conn) < 0) { + connection_close_unattached_ap(conn, END_STREAM_REASON_CANT_ATTACH); + return -1; + } + return 0; } else { conn->state = AP_CONN_STATE_CONTROLLER_WAIT; return 0; @@ -956,6 +973,7 @@ static int connection_ap_handshake_process_socks(connection_t *conn) { * building all the circuits and then realizing it won't work. */ log_fn(LOG_WARN,"Resolve requests to hidden services not allowed. Failing."); connection_ap_handshake_socks_resolved(conn,RESOLVED_TYPE_ERROR,0,NULL); + connection_close_unattached_ap(conn, END_STREAM_REASON_ALREADY_SOCKS_REPLIED); return -1; } @@ -965,6 +983,7 @@ static int connection_ap_handshake_process_socks(connection_t *conn) { r = rend_cache_lookup_entry(conn->rend_query, &entry); if (r<0) { log_fn(LOG_WARN,"Invalid service descriptor %s", conn->rend_query); + connection_close_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL); return -1; } if (r==0) { @@ -978,7 +997,11 @@ static int connection_ap_handshake_process_socks(connection_t *conn) { if (time(NULL) - entry->received < NUM_SECONDS_BEFORE_REFETCH) { conn->state = AP_CONN_STATE_CIRCUIT_WAIT; log_fn(LOG_INFO, "Descriptor is here and fresh enough. Great."); - return connection_ap_handshake_attach_circuit(conn); + if (connection_ap_handshake_attach_circuit(conn) < 0) { + connection_close_unattached_ap(conn, END_STREAM_REASON_CANT_ATTACH); + return -1; + } + return 0; } else { conn->state = AP_CONN_STATE_RENDDESC_WAIT; log_fn(LOG_INFO, "Stale descriptor %s. Refetching.", conn->rend_query); @@ -1144,7 +1167,7 @@ int connection_ap_make_bridge(char *address, uint16_t port) { /* attaching to a dirty circuit is fine */ if (connection_ap_handshake_attach_circuit(conn) < 0) { - connection_close_unattached_ap(conn, END_STREAM_REASON_MISC); + connection_close_unattached_ap(conn, END_STREAM_REASON_CANT_ATTACH); tor_close_socket(fd[1]); return -1; } diff --git a/src/or/control.c b/src/or/control.c index 68c8ded6ce..03f0c20317 100644 --- a/src/or/control.c +++ b/src/or/control.c @@ -736,7 +736,7 @@ static int handle_control_attachstream(connection_t *conn, uint32_t len, if (!circ_id) { ap_conn->state = AP_CONN_STATE_CIRCUIT_WAIT; if (connection_ap_handshake_attach_circuit(ap_conn)<0) - connection_close_unattached_ap(ap_conn, END_STREAM_REASON_MISC); + connection_close_unattached_ap(ap_conn, END_STREAM_REASON_CANT_ATTACH); send_control_done(conn); return 0; } diff --git a/src/or/main.c b/src/or/main.c index 860696197e..22c89a29b2 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -478,8 +478,7 @@ void directory_all_unreachable(time_t now) { AP_CONN_STATE_CIRCUIT_WAIT))) { log_fn(LOG_NOTICE,"Network down? Failing connection to '%s:%d'.", conn->socks_request->address, conn->socks_request->port); - connection_close_unattached_ap(conn, END_STREAM_REASON_TIMEOUT); -// XXX should maybe reflect SOCKS5_NET_UNREACHABLE here. what reason is that? + connection_close_unattached_ap(conn, END_STREAM_REASON_NET_UNREACHABLE); } } diff --git a/src/or/or.h b/src/or/or.h index c040c588c1..8c0d144b6a 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -430,6 +430,14 @@ typedef enum { #define END_STREAM_REASON_CONNRESET 12 #define END_STREAM_REASON_TORPROTOCOL 13 +/* These high-numbered end reasons are not part of the official spec, + * and are not intended to be put in relay end cells. They are here + * to be more informative when sending back socks replies to the + * application. */ +#define END_STREAM_REASON_ALREADY_SOCKS_REPLIED 256 +#define END_STREAM_REASON_CANT_ATTACH 257 +#define END_STREAM_REASON_NET_UNREACHABLE 258 + #define RESOLVED_TYPE_HOSTNAME 0 #define RESOLVED_TYPE_IPV4 4 #define RESOLVED_TYPE_IPV6 6 diff --git a/src/or/relay.c b/src/or/relay.c index 32277fd82d..4b79f17463 100644 --- a/src/or/relay.c +++ b/src/or/relay.c @@ -500,13 +500,13 @@ connection_edge_end_reason_socks5_response(int reason) case END_STREAM_REASON_CONNECTREFUSED: return SOCKS5_CONNECTION_REFUSED; case END_STREAM_REASON_EXITPOLICY: - return SOCKS5_CONNECTION_REFUSED; // XXX should be SOCKS5_NOT_ALLOWED ? + return SOCKS5_NOT_ALLOWED; case END_STREAM_REASON_DESTROY: return SOCKS5_GENERAL_ERROR; case END_STREAM_REASON_DONE: return SOCKS5_SUCCEEDED; case END_STREAM_REASON_TIMEOUT: - return SOCKS5_TTL_EXPIRED; // XXX is this correct? + return SOCKS5_TTL_EXPIRED; case END_STREAM_REASON_RESOURCELIMIT: return SOCKS5_GENERAL_ERROR; case END_STREAM_REASON_HIBERNATING: @@ -517,6 +517,13 @@ connection_edge_end_reason_socks5_response(int reason) return SOCKS5_CONNECTION_REFUSED; case END_STREAM_REASON_TORPROTOCOL: return SOCKS5_GENERAL_ERROR; + + case END_STREAM_REASON_ALREADY_SOCKS_REPLIED: + return SOCKS5_SUCCEEDED; /* never used */ + case END_STREAM_REASON_CANT_ATTACH: + return SOCKS5_GENERAL_ERROR; + case END_STREAM_REASON_NET_UNREACHABLE: + return SOCKS5_NET_UNREACHABLE; default: log_fn(LOG_WARN,"Reason for ending (%d) not recognized.",reason); return SOCKS5_GENERAL_ERROR; @@ -716,7 +723,7 @@ connection_edge_process_relay_cell_not_open( cell->payload[RELAY_HEADER_SIZE], /*answer_type*/ cell->payload[RELAY_HEADER_SIZE+1], /*answer_len*/ cell->payload+RELAY_HEADER_SIZE+2); /* answer */ - connection_close_unattached_ap(conn, END_STREAM_REASON_DONE); + connection_close_unattached_ap(conn, END_STREAM_REASON_ALREADY_SOCKS_REPLIED); return 0; } diff --git a/src/or/rendclient.c b/src/or/rendclient.c index 2b1970f95e..b874802666 100644 --- a/src/or/rendclient.c +++ b/src/or/rendclient.c @@ -394,7 +394,7 @@ void rend_client_desc_here(char *query) { if (connection_ap_handshake_attach_circuit(conn) < 0) { /* it will never work */ log_fn(LOG_WARN,"attaching to a rend circ failed. Closing conn."); - connection_close_unattached_ap(conn, END_STREAM_REASON_MISC); + connection_close_unattached_ap(conn, END_STREAM_REASON_CANT_ATTACH); } tor_assert(conn->state != AP_CONN_STATE_RENDDESC_WAIT); /* avoid loop */ } else { /* 404, or fetch didn't get that far */