[or-cvs] Implement RESOLVE/RESOLVED cells and socks resolve code
Nick Mathewson
nickm at seul.org
Thu Jun 17 18:13:13 UTC 2004
Update of /home/or/cvsroot/src/or
In directory moria.mit.edu:/tmp/cvs-serv430/src/or
Modified Files:
buffers.c circuituse.c connection.c connection_edge.c dns.c
or.h relay.c
Log Message:
Implement RESOLVE/RESOLVED cells and socks resolve code
Index: buffers.c
===================================================================
RCS file: /home/or/cvsroot/src/or/buffers.c,v
retrieving revision 1.95
retrieving revision 1.96
diff -u -d -r1.95 -r1.96
--- buffers.c 1 Jun 2004 17:31:13 -0000 1.95
+++ buffers.c 17 Jun 2004 18:13:09 -0000 1.96
@@ -409,6 +409,9 @@
return 1;
}
+#define SOCKS_COMMAND_CONNECT 0x01
+#define SOCKS_COMMAND_RESOLVE 0xF0
+
/** There is a (possibly incomplete) socks handshake on <b>buf</b>, of one
* of the forms
* - socks4: "socksheader username\\0"
@@ -467,8 +470,12 @@
log_fn(LOG_DEBUG,"socks5: checking request");
if(buf->datalen < 8) /* basic info plus >=2 for addr plus 2 for port */
return 0; /* not yet */
- if(*(buf->mem+1) != 1) { /* not a connect? we don't support it. */
- log_fn(LOG_WARN,"socks5: command %d not '1'. Rejecting.",*(buf->mem+1));
+ req->command = (unsigned char) *(buf->mem+1);
+ if(req->command != SOCKS_COMMAND_CONNECT &&
+ req->command != SOCKS_COMMAND_RESOLVE) {
+ /* not a connect or resolve? we don't support it. */
+ log_fn(LOG_WARN,"socks5: command %d not recognized. Rejecting.",
+ req->command);
return -1;
}
switch(*(buf->mem+3)) { /* address type */
@@ -516,14 +523,18 @@
if(buf->datalen < SOCKS4_NETWORK_LEN) /* basic info available? */
return 0; /* not yet */
- if(*(buf->mem+1) != 1) { /* not a connect? we don't support it. */
- log_fn(LOG_WARN,"socks4: command %d not '1'. Rejecting.",*(buf->mem+1));
+ req->command = (unsigned char) *(buf->mem+1);
+ if(req->command != SOCKS_COMMAND_CONNECT &&
+ req->command != SOCKS_COMMAND_RESOLVE) {
+ /* not a connect or resolve? we don't support it. */
+ log_fn(LOG_WARN,"socks4: command %d not recognized. Rejecting.",
+ req->command);
return -1;
}
req->port = ntohs(*(uint16_t*)(buf->mem+2));
destip = ntohl(*(uint32_t*)(buf->mem+4));
- if(!req->port || !destip) {
+ if((!req->port && req->command!=SOCKS_COMMAND_RESOLVE) || !destip) {
log_fn(LOG_WARN,"socks4: Port or DestIP is zero. Rejecting.");
return -1;
}
Index: circuituse.c
===================================================================
RCS file: /home/or/cvsroot/src/or/circuituse.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- circuituse.c 15 May 2004 07:21:24 -0000 1.2
+++ circuituse.c 17 Jun 2004 18:13:09 -0000 1.3
@@ -73,7 +73,14 @@
return 0; /* this circuit is screwed and doesn't know it yet */
}
- if(purpose == CIRCUIT_PURPOSE_C_GENERAL) {
+ if (conn->socks_request &&
+ conn->socks_request->command == SOCKS_COMMAND_RESOLVE) {
+ /* 0.0.7 servers and earlier don't support DNS resolution. There are no
+ * ORs running code before 0.0.7, so we only worry about 0.0.7. Once all
+ * servers are running 0.0.8, remove this check. */
+ if (!strncmp(exitrouter->platform, "Tor 0.0.7", 9))
+ return 0;
+ } else if(purpose == CIRCUIT_PURPOSE_C_GENERAL) {
if(connection_ap_can_use_exit(conn, exitrouter) == ADDR_POLICY_REJECTED) {
/* can't exit from this router */
return 0;
@@ -618,10 +625,12 @@
circuit_t **circp) {
circuit_t *circ;
uint32_t addr;
+ int is_resolve;
tor_assert(conn);
tor_assert(circp);
tor_assert(conn->state == AP_CONN_STATE_CIRCUIT_WAIT);
+ is_resolve = conn->socks_request->command == SOCKS_COMMAND_RESOLVE;
circ = circuit_get_best(conn, 1, desired_circuit_purpose);
@@ -630,7 +639,8 @@
return 1; /* we're happy */
}
- if(!connection_edge_is_rendezvous_stream(conn)) { /* general purpose circ */
+ /* Do we need to check exit policy? */
+ if(!is_resolve && !connection_edge_is_rendezvous_stream(conn)) {
addr = client_dns_lookup_entry(conn->socks_request->address);
if(router_exit_policy_all_routers_reject(addr, conn->socks_request->port)) {
log_fn(LOG_WARN,"No Tor server exists that allows exit to %s:%d. Rejecting.",
@@ -742,10 +752,13 @@
circ->timestamp_dirty = time(NULL);
link_apconn_to_circ(conn, circ);
- connection_ap_handshake_send_begin(conn, circ);
+ tor_assert(conn->socks_request);
+ if (conn->socks_request->command == SOCKS_COMMAND_CONNECT)
+ connection_ap_handshake_send_begin(conn, circ);
+ else
+ connection_ap_handshake_send_resolve(conn, circ);
return 1;
-
} else { /* we're a rendezvous conn */
circuit_t *rendcirc=NULL, *introcirc=NULL;
Index: connection.c
===================================================================
RCS file: /home/or/cvsroot/src/or/connection.c,v
retrieving revision 1.231
retrieving revision 1.232
diff -u -d -r1.231 -r1.232
--- connection.c 5 Jun 2004 01:50:35 -0000 1.231
+++ connection.c 17 Jun 2004 18:13:09 -0000 1.232
@@ -1276,7 +1276,10 @@
} else {
tor_assert(!conn->socks_request);
}
- if(conn->type != CONN_TYPE_DIR) {
+ if (conn->type == CONN_TYPE_EXIT) {
+ tor_assert(conn->purpose == EXIT_PURPOSE_CONNECT ||
+ conn->purpose == EXIT_PURPOSE_RESOLVE);
+ } else if(conn->type != CONN_TYPE_DIR) {
tor_assert(!conn->purpose); /* only used for dir types currently */
}
Index: connection_edge.c
===================================================================
RCS file: /home/or/cvsroot/src/or/connection_edge.c,v
retrieving revision 1.193
retrieving revision 1.194
diff -u -d -r1.193 -r1.194
--- connection_edge.c 2 Jun 2004 18:32:24 -0000 1.193
+++ connection_edge.c 17 Jun 2004 18:13:09 -0000 1.194
@@ -371,6 +371,23 @@
return sockshere;
} /* else socks handshake is done, continue processing */
+ if (socks->command == SOCKS_COMMAND_RESOLVE) {
+ /* Reply to resolves immediately if we can. */
+ if (strlen(socks->address) > RELAY_PAYLOAD_SIZE) {
+ connection_ap_handshake_socks_resolved(conn,RESOLVED_TYPE_ERROR,0,NULL);
+ conn->socks_request->has_finished = 1;
+ connection_mark_for_close(conn);
+ }
+ uint32_t answer = htonl(client_dns_lookup_entry(socks->address));
+ if (answer) {
+ connection_ap_handshake_socks_resolved(conn,RESOLVED_TYPE_IPV4,4,
+ (char*)&answer);
+ conn->socks_request->has_finished = 1;
+ connection_mark_for_close(conn);
+ return 0;
+ }
+ }
+
/* this call _modifies_ socks->address iff it's a hidden-service request */
if (rend_parse_rendezvous_address(socks->address) < 0) {
/* normal request */
@@ -487,6 +504,46 @@
return 0;
}
+/** Write a relay resolve cell, using destaddr and destport from ap_conn's
+ * socks_request field, and send it down circ.
+ *
+ * If ap_conn is broken, mark it for close and return -1. Else return 0.
+ */
+int connection_ap_handshake_send_resolve(connection_t *ap_conn, circuit_t *circ)
+{
+ int payload_len;
+ const char *string_addr;
+
+ tor_assert(ap_conn->type == CONN_TYPE_AP);
+ tor_assert(ap_conn->state == AP_CONN_STATE_CIRCUIT_WAIT);
+ tor_assert(ap_conn->socks_request);
+ tor_assert(ap_conn->socks_request->command == SOCKS_COMMAND_RESOLVE);
+ tor_assert(circ->purpose == CIRCUIT_PURPOSE_C_GENERAL);
+
+ ap_conn->stream_id = get_unique_stream_id_by_circ(circ);
+ if (ap_conn->stream_id==0) {
+ /* Don't send end: there is no 'other side' yet */
+ ap_conn->has_sent_end = 1;
+ connection_mark_for_close(ap_conn);
+ circuit_mark_for_close(circ);
+ return -1;
+ }
+
+ string_addr = ap_conn->socks_request->address;
+ payload_len = strlen(string_addr);
+ tor_assert(strlen(string_addr) <= RELAY_PAYLOAD_SIZE);
+
+ log_fn(LOG_DEBUG,"Sending relay cell to begin stream %d.",ap_conn->stream_id);
+
+ if(connection_edge_send_command(ap_conn, circ, RELAY_COMMAND_RESOLVE,
+ string_addr, payload_len, ap_conn->cpath_layer) < 0)
+ return -1; /* circuit is closed, don't continue */
+
+ ap_conn->state = AP_CONN_STATE_RESOLVE_WAIT;
+ log_fn(LOG_INFO,"Address sent for resolve, ap socket %d, n_circ_id %d",ap_conn->s,circ->n_circ_id);
+ return 0;
+}
+
/** Make an AP connection_t, do a socketpair and attach one side
* to the conn, connection_add it, initialize it to circuit_wait,
* and call connection_ap_handshake_attach_circuit(conn) on it.
@@ -544,6 +601,59 @@
return fd[1];
}
+void connection_ap_handshake_socks_resolved(connection_t *conn,
+ int answer_type,
+ int answer_len,
+ const char *answer)
+{
+ char buf[256];
+ int replylen;
+
+ if (answer_type == RESOLVED_TYPE_IPV4) {
+ uint32_t a = get_uint32(answer);
+ client_dns_set_entry(conn->socks_request->address, ntohl(a));
+ }
+
+ if (conn->socks_request->socks_version == 4) {
+ buf[0] = 0x00; /* version */
+ if (answer_type == RESOLVED_TYPE_IPV4 && answer_len == 4) {
+ buf[1] = 90; /* "Granted" */
+ set_uint16(buf+2, 0);
+ memcpy(buf+4, answer, 4); /* address */
+ replylen = SOCKS4_NETWORK_LEN;
+ } else {
+ buf[1] = 91; /* "error" */
+ memset(buf+2, 0, 6);
+ replylen = SOCKS4_NETWORK_LEN;
+ }
+ } else {
+ /* SOCKS5 */
+ buf[0] = 0x05; /* version */
+ if (answer_type == RESOLVED_TYPE_IPV4 && answer_len == 4) {
+ buf[1] = 0; /* 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[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 */
+ memset(buf+2, 0, 8);
+ replylen = 10;
+ }
+ }
+ connection_ap_handshake_socks_reply(conn, buf, replylen,
+ answer_type == RESOLVED_TYPE_IPV4 ||
+ answer_type == RESOLVED_TYPE_IPV6);
+}
+
/** Send a socks reply to stream <b>conn</b>, using the appropriate
* socks version, etc.
*
@@ -631,6 +741,7 @@
log_fn(LOG_DEBUG,"Creating new exit connection.");
n_stream = connection_new(CONN_TYPE_EXIT);
+ n_stream->purpose = EXIT_PURPOSE_CONNECT;
n_stream->stream_id = rh.stream_id;
n_stream->port = atoi(colon+1);
@@ -694,6 +805,52 @@
return 0;
}
+/**
+ * Called when we receive a RELAY_RESOLVE cell 'cell' along the circuit 'circ';
+ * begin resolving the hostname, and (eventually) reply with a RESOLVED cell.
+ */
+int connection_exit_begin_resolve(cell_t *cell, circuit_t *circ) {
+ connection_t *dummy_conn;
+ relay_header_t rh;
+
+ assert_circuit_ok(circ);
+ relay_header_unpack(&rh, cell->payload);
+
+
+ /* This 'dummy_conn' only exists to remember the stream ID
+ * associated with the resolve request; and to make the
+ * implementation of dns.c more uniform. (We really only need to
+ * remember the circuit, the stream ID, and the hostname to be
+ * resolved; but if we didn't store them in a connection like this,
+ * the housekeeping in dns.c would get way more complicated.)
+ */
+ dummy_conn = connection_new(CONN_TYPE_EXIT);
+ dummy_conn->stream_id = rh.stream_id;
+ dummy_conn->address = tor_strndup(cell->payload+RELAY_HEADER_SIZE,
+ rh.length);
+ dummy_conn->port = 0;
+ dummy_conn->state = EXIT_CONN_STATE_RESOLVEFAILED;
+ dummy_conn->purpose = EXIT_PURPOSE_RESOLVE;
+
+ /* send it off to the gethostbyname farm */
+ switch(dns_resolve(dummy_conn)) {
+ case 1: /* resolve worked; resolved cell was sent. */
+ connection_free(dummy_conn);
+ return 0;
+ case -1: /* resolve failed; resolved cell was sent. */
+ log_fn(LOG_INFO,"Resolve failed (%s).",dummy_conn->address);
+ connection_free(dummy_conn);
+ break;
+ case 0: /* resolve added to pending list */
+ /* add it into the linked list of resolving_streams on this circuit */
+ dummy_conn->next_stream = circ->resolving_streams;
+ circ->resolving_streams = dummy_conn;
+ assert_circuit_ok(circ);
+ ;
+ }
+ return 0;
+}
+
/** Connect to conn's specified addr and port. If it worked, conn
* has now been added to the connection_array.
*
@@ -776,6 +933,12 @@
log_fn(LOG_DEBUG,"considering nickname %s, for address %s / port %d:",
exit->nickname, conn->socks_request->address,
conn->socks_request->port);
+ if (conn->socks_request->command == SOCKS_COMMAND_RESOLVE) {
+ /* 0.0.7 servers and earlier don't support DNS resolution. There are no
+ * ORs running code before 0.0.7, so we only worry about 0.0.7. Once all
+ * servers are running 0.0.8, remove this check. */
+ return strncmp(exit->platform, "Tor 0.0.7", 9) ? 1 : 0;
+ }
addr = client_dns_lookup_entry(conn->socks_request->address);
return router_compare_addr_to_exit_policy(addr,
conn->socks_request->port, exit->exit_policy);
Index: dns.c
===================================================================
RCS file: /home/or/cvsroot/src/or/dns.c,v
retrieving revision 1.99
retrieving revision 1.100
diff -u -d -r1.99 -r1.100
--- dns.c 6 Jun 2004 03:38:31 -0000 1.99
+++ dns.c 17 Jun 2004 18:13:09 -0000 1.100
@@ -71,6 +71,7 @@
static int dnsworker_main(void *data);
static int spawn_dnsworker(void);
static void spawn_enough_dnsworkers(void);
+static void send_resolved_cell(connection_t *conn, uint8_t answer_type);
/** Splay tree of cached_resolve objects. */
static SPLAY_HEAD(cache_tree, cached_resolve) cache_root;
@@ -141,6 +142,34 @@
}
}
+static void send_resolved_cell(connection_t *conn, uint8_t answer_type)
+{
+ char buf[RELAY_PAYLOAD_SIZE];
+ int buflen;
+
+ buf[0] = answer_type;
+
+ switch (answer_type)
+ {
+ case RESOLVED_TYPE_IPV4:
+ buf[1] = 4;
+ set_uint32(buf+2, htonl(conn->addr));
+ buflen = 6;
+ break;
+ case RESOLVED_TYPE_ERROR_TRANSIENT:
+ case RESOLVED_TYPE_ERROR:
+ buf[1] = 24; /* length of "error resolving hostname" */
+ strcpy(buf+2, "error resolving hostname");
+ buflen = 26;
+ break;
+ default:
+ tor_assert(0);
+ }
+ connection_edge_send_command(conn, circuit_get_by_conn(conn),
+ RELAY_COMMAND_RESOLVED, buf, buflen,
+ conn->cpath_layer);
+}
+
/** See if we have a cache entry for <b>exitconn</b>-\>address. if so,
* if resolve valid, put it into <b>exitconn</b>-\>addr and return 1.
* If resolve failed, return -1.
@@ -179,7 +208,8 @@
switch(resolve->state) {
case CACHE_STATE_PENDING:
/* add us to the pending list */
- pending_connection = tor_malloc(sizeof(struct pending_connection_t));
+ pending_connection = tor_malloc_zero(
+ sizeof(struct pending_connection_t));
pending_connection->conn = exitconn;
pending_connection->next = resolve->pending_connections;
resolve->pending_connections = pending_connection;
@@ -191,8 +221,12 @@
exitconn->addr = resolve->addr;
log_fn(LOG_DEBUG,"Connection (fd %d) found cached answer for '%s'",
exitconn->s, exitconn->address);
+ if (exitconn->purpose == EXIT_PURPOSE_RESOLVE)
+ send_resolved_cell(exitconn, RESOLVED_TYPE_IPV4);
return 1;
case CACHE_STATE_FAILED:
+ if (exitconn->purpose == EXIT_PURPOSE_RESOLVE)
+ send_resolved_cell(exitconn, RESOLVED_TYPE_ERROR);
return -1;
}
tor_assert(0);
@@ -205,7 +239,7 @@
resolve->address[MAX_ADDRESSLEN-1] = 0;
/* add us to the pending list */
- pending_connection = tor_malloc(sizeof(struct pending_connection_t));
+ pending_connection = tor_malloc_zero(sizeof(struct pending_connection_t));
pending_connection->conn = exitconn;
pending_connection->next = NULL;
resolve->pending_connections = pending_connection;
@@ -240,6 +274,7 @@
if(!dnsconn) {
log_fn(LOG_WARN,"no idle dns workers. Failing.");
dns_cancel_pending_resolve(exitconn->address);
+ send_resolved_cell(exitconn, RESOLVED_TYPE_ERROR_TRANSIENT);
return -1;
}
@@ -453,28 +488,42 @@
pend = resolve->pending_connections;
assert_connection_ok(pend->conn,time(NULL));
pend->conn->addr = resolve->addr;
+ pendconn = pend->conn; /* don't pass complex things to the
+ connection_mark_for_close macro */
if(resolve->state == CACHE_STATE_FAILED) {
- pendconn = pend->conn; /* don't pass complex things to the
- connection_mark_for_close macro */
/* prevent double-remove. */
pendconn->state = EXIT_CONN_STATE_RESOLVEFAILED;
circuit_detach_stream(circuit_get_by_conn(pendconn), pendconn);
- connection_edge_end(pendconn, END_STREAM_REASON_MISC, pendconn->cpath_layer);
+ if (pendconn->purpose == EXIT_PURPOSE_CONNECT)
+ connection_edge_end(pendconn, END_STREAM_REASON_MISC, pendconn->cpath_layer);
+ else
+ send_resolved_cell(pendconn, RESOLVED_TYPE_ERROR);
connection_free(pendconn);
} else {
- /* prevent double-remove. */
- pend->conn->state = EXIT_CONN_STATE_CONNECTING;
+ if (pendconn->purpose == EXIT_PURPOSE_CONNECT) {
+ /* prevent double-remove. */
+ pend->conn->state = EXIT_CONN_STATE_CONNECTING;
- circ = circuit_get_by_conn(pend->conn);
- assert(circ);
- /* unlink pend->conn from resolving_streams, */
- circuit_detach_stream(circ, pend->conn);
- /* and link it to n_streams */
- pend->conn->next_stream = circ->n_streams;
- circ->n_streams = pend->conn;
+ circ = circuit_get_by_conn(pend->conn);
+ tor_assert(circ);
+ /* unlink pend->conn from resolving_streams, */
+ circuit_detach_stream(circ, pend->conn);
+ /* and link it to n_streams */
+ pend->conn->next_stream = circ->n_streams;
+ circ->n_streams = pend->conn;
- connection_exit_connect(pend->conn);
+ connection_exit_connect(pend->conn);
+ } else {
+ /* prevent double-remove. This isn't really an accurate state,
+ * but it does the right thing. */
+ pendconn->state = EXIT_CONN_STATE_RESOLVEFAILED;
+ send_resolved_cell(pendconn, RESOLVED_TYPE_IPV4);
+ circ = circuit_get_by_conn(pendconn);
+ tor_assert(circ);
+ circuit_detach_stream(circ, pendconn);
+ connection_free(pendconn);
+ }
}
resolve->pending_connections = pend->next;
tor_free(pend);
Index: or.h
===================================================================
RCS file: /home/or/cvsroot/src/or/or.h,v
retrieving revision 1.368
retrieving revision 1.369
diff -u -d -r1.368 -r1.369
--- or.h 16 Jun 2004 21:08:29 -0000 1.368
+++ or.h 17 Jun 2004 18:13:09 -0000 1.369
@@ -221,9 +221,11 @@
#define AP_CONN_STATE_CIRCUIT_WAIT 7
/** State for a SOCKS connection: sent BEGIN, waiting for CONNECTED. */
#define AP_CONN_STATE_CONNECT_WAIT 8
+/** State for a SOCKS connection: send RESOLVE, waiting for RESOLVED. */
+#define AP_CONN_STATE_RESOLVE_WAIT 9
/** State for a SOCKS connection: ready to send and receive. */
-#define AP_CONN_STATE_OPEN 9
-#define _AP_CONN_STATE_MAX 9
+#define AP_CONN_STATE_OPEN 10
+#define _AP_CONN_STATE_MAX 10
#define _DIR_CONN_STATE_MIN 1
/** State for connection to directory server: waiting for connect(). */
@@ -259,6 +261,11 @@
#define DIR_PURPOSE_SERVER 7
#define _DIR_PURPOSE_MAX 7
+#define _EXIT_PURPOSE_MIN 1
+#define EXIT_PURPOSE_CONNECT 1
+#define EXIT_PURPOSE_RESOLVE 2
+#define _EXIT_PURPOSE_MAX 2
+
/** Circuit state: I'm the OP, still haven't done all my handshakes. */
#define CIRCUIT_STATE_BUILDING 0
/** Circuit state: Waiting to process the onionskin. */
@@ -371,6 +378,11 @@
#define END_STREAM_REASON_TIMEOUT 7
#define _MAX_END_STREAM_REASON 7
+#define RESOLVED_TYPE_IPV4 4
+#define RESOLVED_TYPE_IPV6 6
+#define RESOLVED_TYPE_ERROR_TRANSIENT 0xF0
+#define RESOLVED_TYPE_ERROR 0xF1
+
/** Length of 'y' portion of 'y.onion' URL. */
#define REND_SERVICE_ID_LEN 16
@@ -841,9 +853,12 @@
/* XXX are these good enough defaults? */
#define MAX_SOCKS_REPLY_LEN 1024
#define MAX_SOCKS_ADDR_LEN 256
+#define SOCKS_COMMAND_CONNECT 0x01
+#define SOCKS_COMMAND_RESOLVE 0xF0
/** 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 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,
@@ -1048,13 +1063,18 @@
int connection_edge_finished_connecting(connection_t *conn);
int connection_ap_handshake_send_begin(connection_t *ap_conn, circuit_t *circ);
+int connection_ap_handshake_send_resolve(connection_t *ap_conn, circuit_t *circ);
int connection_ap_make_bridge(char *address, uint16_t port);
-
void connection_ap_handshake_socks_reply(connection_t *conn, char *reply,
int replylen, char success);
+void connection_ap_handshake_socks_resolved(connection_t *conn,
+ int answer_type,
+ int answer_len,
+ const char *answer);
int connection_exit_begin_conn(cell_t *cell, circuit_t *circ);
+int connection_exit_begin_resolve(cell_t *cell, circuit_t *circ);
void connection_exit_connect(connection_t *conn);
int connection_edge_is_rendezvous_stream(connection_t *conn);
int connection_ap_can_use_exit(connection_t *conn, routerinfo_t *exit);
Index: relay.c
===================================================================
RCS file: /home/or/cvsroot/src/or/relay.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- relay.c 15 May 2004 07:21:25 -0000 1.3
+++ relay.c 17 Jun 2004 18:13:09 -0000 1.4
@@ -562,6 +562,26 @@
}
return 0;
}
+ if(conn->type == CONN_TYPE_AP && rh->command == RELAY_COMMAND_RESOLVED) {
+ if (conn->state != AP_CONN_STATE_RESOLVE_WAIT) {
+ log_fn(LOG_WARN,"Got a 'resolved' cell while not in state resolve_wait. Dropping.");
+ return 0;
+ }
+ tor_assert(conn->socks_request->command == SOCKS_COMMAND_RESOLVE);
+ if (rh->length < 2 || cell->payload[RELAY_HEADER_SIZE+1]+2>rh->length) {
+ log_fn(LOG_WARN, "Dropping malformed 'resolved' cell");
+ connection_edge_end(conn, END_STREAM_REASON_MISC, conn->cpath_layer);
+ connection_mark_for_close(conn);
+ return 0;
+ }
+ connection_ap_handshake_socks_resolved(conn,
+ cell->payload[RELAY_HEADER_SIZE], /*answer_type*/
+ cell->payload[RELAY_HEADER_SIZE+1], /*answer_len*/
+ cell->payload+RELAY_HEADER_SIZE+2); /* answer */
+ conn->socks_request->has_finished = 1;
+ connection_mark_for_close(conn);
+ return 0;
+ }
log_fn(LOG_WARN,"Got an unexpected relay command %d, in state %d (%s). Closing.",
rh->command, conn->state, conn_state_to_string[conn->type][conn->state]);
@@ -744,6 +764,27 @@
connection_start_reading(conn);
connection_edge_package_raw_inbuf(conn); /* handle whatever might still be on the inbuf */
return 0;
+ case RELAY_COMMAND_RESOLVE:
+ if (layer_hint) {
+ log_fn(LOG_WARN,"resolve request unsupported at AP; dropping.");
+ return 0;
+ } else if (conn) {
+ log_fn(LOG_WARN, "resolve request for known stream; dropping.");
+ return 0;
+ } else if (circ->purpose != CIRCUIT_PURPOSE_OR) {
+ log_fn(LOG_WARN, "resolve request on circ with purpose %d; dropping",
+ circ->purpose);
+ return 0;
+ }
+ connection_exit_begin_resolve(cell, circ);
+ return 0;
+ case RELAY_COMMAND_RESOLVED:
+ if(conn) {
+ log_fn(LOG_WARN,"'resolved' unsupported while open. Closing circ.");
+ return -1;
+ }
+ log_fn(LOG_INFO,"'resolved' received, no conn attached anymore. Ignoring.");
+ return 0;
case RELAY_COMMAND_ESTABLISH_INTRO:
case RELAY_COMMAND_ESTABLISH_RENDEZVOUS:
case RELAY_COMMAND_INTRODUCE1:
More information about the tor-commits
mailing list