Forward-port new reasons; clean up code more; add code to convert new reasons to SOCKS5 reply codes; add code to convert errnos to reasons. New code still needs to get invoked.

svn:r3719
This commit is contained in:
Nick Mathewson 2005-03-01 22:16:15 +00:00
parent 59ec8ca3f1
commit 4ddf768a4f
6 changed files with 131 additions and 32 deletions

View File

@ -73,17 +73,15 @@ R . HTTPS proxy for OR CONNECT stuff. (For outgoing SSL connections to
o If a version is later than the last in its series, but a version
in the next series is recommended, that doesn't mean it's bad.
- Do end reasons better
- Start using RESOURCELIMIT more.
- Try to use MISC a lot less.
. Start using RESOURCELIMIT more.
. Try to use MISC a lot less.
- bug: if the exit node fails to create a socket (e.g. because it
has too many open), we will get a generic stream end response.
- niels's "did it fail because conn refused or timeout or what"
. niels's "did it fail because conn refused or timeout or what"
relay end feature.
N - Realize that unrecognized end reasons are probably features rather than
o Realize that unrecognized end reasons are probably features rather than
bugs. (backport to 009x)
N - Start recognizing, but maybe not yet generating, more reasons and
needed -- aim to eliminate misc. (backport to 009x)
N - Feed end reason back into SOCK5 as reasonable.
N . Feed end reason back into SOCK5 as reasonable.
R o cache .foo.exit names better, or differently, or not.
N - make !advertised_server_mode() ORs fetch dirs less often.
N - Clean up NT service code even more. Document it. Enable it by default.

View File

@ -472,7 +472,7 @@ int fetch_from_buf_socks(buf_t *buf, socks_request_t *req) {
if (!nummethods || !memchr(buf->mem+2, 0, nummethods)) {
log_fn(LOG_WARN,"socks5: offered methods don't include 'no auth'. Rejecting.");
req->replylen = 2; /* 2 bytes of response */
req->reply[0] = 5; /* socks5 reply */
req->reply[0] = 5;
req->reply[1] = '\xFF'; /* reject all methods */
return -1;
}
@ -480,7 +480,7 @@ int fetch_from_buf_socks(buf_t *buf, socks_request_t *req) {
req->replylen = 2; /* 2 bytes of response */
req->reply[0] = 5; /* socks5 reply */
req->reply[1] = 0; /* choose the 'no auth' method */
req->reply[1] = SOCKS5_SUCCEEDED;
req->socks_version = 5; /* remember that we've already negotiated auth */
log_fn(LOG_DEBUG,"socks5: accepted method 0");
return 0;

View File

@ -914,7 +914,7 @@ loop_again:
connection_close_immediate(conn); /* Don't flush; connection is dead. */
if (CONN_IS_EDGE(conn)) {
connection_edge_end(conn, (char)(connection_state_is_open(conn) ?
END_STREAM_REASON_MISC : END_STREAM_REASON_CONNECTFAILED),
END_STREAM_REASON_MISC : END_STREAM_REASON_CONNECTREFUSED),
conn->cpath_layer);
}
connection_mark_for_close(conn);
@ -1092,7 +1092,7 @@ int connection_handle_write(connection_t *conn) {
if (!ERRNO_IS_CONN_EINPROGRESS(e)) {
log_fn(LOG_INFO,"in-progress connect failed. Removing.");
if (CONN_IS_EDGE(conn))
connection_edge_end(conn, END_STREAM_REASON_CONNECTFAILED,
connection_edge_end(conn, END_STREAM_REASON_CONNECTREFUSED,
conn->cpath_layer);
connection_close_immediate(conn);

View File

@ -875,21 +875,21 @@ void connection_ap_handshake_socks_resolved(connection_t *conn,
/* SOCKS5 */
buf[0] = 0x05; /* version */
if (answer_type == RESOLVED_TYPE_IPV4 && answer_len == 4) {
buf[1] = 0; /* succeeded */
buf[1] = SOCKS5_SUCCEEDED;
buf[2] = 0; /* reserved */
buf[3] = 0x01; /* IPv4 address type */
memcpy(buf+4, answer, 4); /* address */
set_uint16(buf+8, 0); /* port == 0. */
replylen = 10;
} else if (answer_type == RESOLVED_TYPE_IPV6 && answer_len == 16) {
buf[1] = 0; /* succeeded */
buf[1] = SOCKS5_SUCCEEDED;
buf[2] = 0; /* reserved */
buf[3] = 0x04; /* IPv6 address type */
memcpy(buf+4, answer, 16); /* address */
set_uint16(buf+20, 0); /* port == 0. */
replylen = 22;
} else {
buf[1] = 0x04; /* host unreachable */
buf[1] = SOCKS5_HOST_UNREACHABLE;
memset(buf+2, 0, 8);
replylen = 10;
}
@ -1156,7 +1156,8 @@ connection_exit_connect(connection_t *conn) {
log_fn(LOG_DEBUG,"about to try connecting");
switch (connection_connect(conn, conn->address, addr, port)) {
case -1:
connection_edge_end(conn, END_STREAM_REASON_CONNECTFAILED, conn->cpath_layer);
connection_edge_end(conn, END_STREAM_REASON_CONNECTREFUSED,
conn->cpath_layer);
circuit_detach_stream(circuit_get_by_conn(conn), conn);
connection_free(conn);
return;

View File

@ -413,16 +413,18 @@ typedef enum {
#define RELAY_COMMAND_RENDEZVOUS_ESTABLISHED 39
#define RELAY_COMMAND_INTRODUCE_ACK 40
#define _MIN_END_STREAM_REASON 1
#define END_STREAM_REASON_MISC 1
#define END_STREAM_REASON_RESOLVEFAILED 2
#define END_STREAM_REASON_CONNECTFAILED 3
#define END_STREAM_REASON_CONNECTREFUSED 3
#define END_STREAM_REASON_EXITPOLICY 4
#define END_STREAM_REASON_DESTROY 5
#define END_STREAM_REASON_DONE 6
#define END_STREAM_REASON_TIMEOUT 7
#define END_STREAM_REASON_RESOURCELIMIT 8
#define _MAX_END_STREAM_REASON 8
/* 8 is unallocated. */
#define END_STREAM_REASON_HIBERNATING 9
#define END_STREAM_REASON_INTERNAL 10
#define END_STREAM_REASON_RESOURCELIMIT 11
#define END_STREAM_REASON_CONNRESET 12
#define RESOLVED_TYPE_IPV4 4
#define RESOLVED_TYPE_IPV6 6
@ -466,6 +468,18 @@ typedef enum {
#define SOCKS4_NETWORK_LEN 8
typedef enum {
SOCKS5_SUCCEEDED = 0x00,
SOCKS5_GENERAL_ERROR = 0x01,
SOCKS5_NOT_ALLOWED = 0x02,
SOCKS5_NET_UNREACHABLE = 0x03,
SOCKS5_HOST_UNREACHABLE = 0x04,
SOCKS5_CONNECTION_REFUSED = 0x05,
SOCKS5_TTL_EXPIRED = 0x06,
SOCKS5_COMMAND_NOT_SUPPORTED = 0x07,
SOCKS5_ADDRESS_TYPE_NOT_SUPPORTED = 0x08,
} socks5_reply_status_t;
/*
* Relay payload:
* Relay command [1 byte]
@ -1512,6 +1526,10 @@ int connection_edge_send_command(connection_t *fromconn, circuit_t *circ,
size_t payload_len, crypt_path_t *cpath_layer);
int connection_edge_package_raw_inbuf(connection_t *conn, int package_partial);
void connection_edge_consider_sending_sendme(connection_t *conn);
socks5_reply_status_t connection_edge_end_reason_sock5_response(char *payload, uint16_t length);
int errno_to_end_reasaon(int e);
extern uint64_t stats_n_data_cells_packaged;
extern uint64_t stats_n_data_bytes_packaged;

View File

@ -457,26 +457,105 @@ int connection_edge_send_command(connection_t *fromconn, circuit_t *circ,
* why the stream is closing.
*/
static const char *
connection_edge_end_reason(char *payload, uint16_t length) {
connection_edge_end_reason_str(char *payload, uint16_t length) {
if (length < 1) {
log_fn(LOG_WARN,"End cell arrived with length 0. Should be at least 1.");
return "MALFORMED";
}
if (*payload < _MIN_END_STREAM_REASON || *payload > _MAX_END_STREAM_REASON) {
log_fn(LOG_WARN,"Reason for ending (%d) not recognized.",*payload);
return "MALFORMED";
}
switch (*payload) {
case END_STREAM_REASON_MISC: return "misc error";
case END_STREAM_REASON_RESOLVEFAILED: return "resolve failed";
case END_STREAM_REASON_CONNECTFAILED: return "connect failed";
case END_STREAM_REASON_CONNECTREFUSED: return "connection refused";
case END_STREAM_REASON_EXITPOLICY: return "exit policy failed";
case END_STREAM_REASON_DESTROY: return "destroyed";
case END_STREAM_REASON_DONE: return "closed normally";
case END_STREAM_REASON_TIMEOUT: return "gave up (timeout)";
case END_STREAM_REASON_HIBERNATING: return "server is hibernating";
case END_STREAM_REASON_INTERNAL: return "internal error at server";
case END_STREAM_REASON_RESOURCELIMIT: return "server out of resources";
case END_STREAM_REASON_CONNRESET: return "connection reset";
default:
log_fn(LOG_WARN,"Reason for ending (%d) not recognized.",*payload);
return "unknown";
}
}
socks5_reply_status_t
connection_edge_end_reason_sock5_response(char *payload, uint16_t length) {
if (length < 1) {
log_fn(LOG_WARN,"End cell arrived with length 0. Should be at least 1.");
return SOCKS5_GENERAL_ERROR;
}
switch (*payload) {
case END_STREAM_REASON_MISC:
return SOCKS5_GENERAL_ERROR;
case END_STREAM_REASON_RESOLVEFAILED:
return SOCKS5_HOST_UNREACHABLE;
case END_STREAM_REASON_CONNECTREFUSED:
return SOCKS5_CONNECTION_REFUSED;
case END_STREAM_REASON_EXITPOLICY:
return SOCKS5_CONNECTION_REFUSED;
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;
case END_STREAM_REASON_RESOURCELIMIT:
return SOCKS5_GENERAL_ERROR;
case END_STREAM_REASON_HIBERNATING:
return SOCKS5_GENERAL_ERROR;
case END_STREAM_REASON_INTERNAL:
return SOCKS5_GENERAL_ERROR;
case END_STREAM_REASON_CONNRESET:
return SOCKS5_CONNECTION_REFUSED;
default:
log_fn(LOG_WARN,"Reason for ending (%d) not recognized.",*payload);
return SOCKS5_GENERAL_ERROR;
}
}
#ifdef MS_WINDOWS
#define E_CASE(s) case s: case WSA ## s
#define W_CASE(s) case s:
#else
#define E_CASE(s) case s
#define W_CASE(s)
#endif
int
errno_to_end_reasaon(int e)
{
switch (e) {
E_CASE(EPIPE):
return END_STREAM_REASON_DONE;
E_CASE(EBADF):
E_CASE(EFAULT):
E_CASE(EINVAL):
E_CASE(EISCONN):
E_CASE(ENOTSOCK):
E_CASE(EPROTONOSUPPORT):
E_CASE(EAFNOSUPPORT):
E_CASE(EACCES):
E_CASE(ENOTCONN):
E_CASE(ENETUNREACH):
return END_STREAM_REASON_INTERNAL;
E_CASE(ECONNREFUSED):
return END_STREAM_REASON_CONNECTREFUSED;
E_CASE(ECONNRESET):
return END_STREAM_REASON_CONNRESET;
E_CASE(ETIMEDOUT):
return END_STREAM_REASON_TIMEOUT;
E_CASE(ENOBUFS):
E_CASE(ENOMEM):
E_CASE(ENFILE):
E_CASE(EMFILE):
return END_STREAM_REASON_RESOURCELIMIT;
default:
log_fn(LOG_INFO, "Didn't recognize errno %d (%s); telling the OP that we are ending a stream for 'misc' reason.",
e, tor_socket_strerror(e));
return END_STREAM_REASON_MISC;
}
tor_assert(0);
return "";
}
/** How many times will I retry a stream that fails due to DNS
@ -567,7 +646,8 @@ connection_edge_process_relay_cell_not_open(
}
}
log_fn(LOG_INFO,"Edge got end (%s) before we're connected. Marking for close.",
connection_edge_end_reason(cell->payload+RELAY_HEADER_SIZE, rh->length));
connection_edge_end_reason_str(cell->payload+RELAY_HEADER_SIZE,
rh->length));
if (CIRCUIT_IS_ORIGIN(circ))
circuit_log_path(LOG_INFO,circ);
conn->has_sent_end = 1; /* we just got an 'end', don't need to send one */
@ -722,14 +802,16 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
case RELAY_COMMAND_END:
if (!conn) {
log_fn(LOG_INFO,"end cell (%s) dropped, unknown stream.",
connection_edge_end_reason(cell->payload+RELAY_HEADER_SIZE, rh.length));
connection_edge_end_reason_str(cell->payload+RELAY_HEADER_SIZE,
rh.length));
return 0;
}
/* XXX add to this log_fn the exit node's nickname? */
log_fn(LOG_INFO,"%d: end cell (%s) for stream %d. Removing stream. Size %d.",
conn->s,
connection_edge_end_reason(cell->payload+RELAY_HEADER_SIZE, rh.length),
conn->stream_id, (int)conn->stream_size);
conn->s,
connection_edge_end_reason_str(cell->payload+RELAY_HEADER_SIZE,
rh.length),
conn->stream_id, (int)conn->stream_size);
#ifdef HALF_OPEN
conn->done_sending = 1;