summaryrefslogtreecommitdiff
path: root/src/or
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2005-03-01 22:16:15 +0000
committerNick Mathewson <nickm@torproject.org>2005-03-01 22:16:15 +0000
commit4ddf768a4fc98bfc2e18a7076bd0397967e3de5e (patch)
tree8049eb9dec027b429757925cce70f724c8151a8e /src/or
parent59ec8ca3f1bbc20a982d1047666cd9483bb07704 (diff)
downloadtor-4ddf768a4fc98bfc2e18a7076bd0397967e3de5e.tar.gz
tor-4ddf768a4fc98bfc2e18a7076bd0397967e3de5e.zip
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
Diffstat (limited to 'src/or')
-rw-r--r--src/or/buffers.c4
-rw-r--r--src/or/connection.c4
-rw-r--r--src/or/connection_edge.c9
-rw-r--r--src/or/or.h26
-rw-r--r--src/or/relay.c108
5 files changed, 126 insertions, 25 deletions
diff --git a/src/or/buffers.c b/src/or/buffers.c
index 0abcd9a828..a6e765eace 100644
--- a/src/or/buffers.c
+++ b/src/or/buffers.c
@@ -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;
diff --git a/src/or/connection.c b/src/or/connection.c
index f44185ac2d..79c98fd280 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -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);
diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c
index cfee2ac5e5..937b282e10 100644
--- a/src/or/connection_edge.c
+++ b/src/or/connection_edge.c
@@ -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;
diff --git a/src/or/or.h b/src/or/or.h
index 55dce9edbf..821d4e08a5 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -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;
diff --git a/src/or/relay.c b/src/or/relay.c
index 866c3d8757..10be51228b 100644
--- a/src/or/relay.c
+++ b/src/or/relay.c
@@ -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;