[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[or-cvs] leave the socks handshake on the inbuf until it"s complete
- To: or-cvs@freehaven.net
- Subject: [or-cvs] leave the socks handshake on the inbuf until it"s complete
- From: arma@seul.org (Roger Dingledine)
- Date: Thu, 18 Sep 2003 04:11:34 -0400 (EDT)
- Delivered-to: archiver@seul.org
- Delivered-to: or-cvs-outgoing@seul.org
- Delivered-to: or-cvs@seul.org
- Delivery-date: Thu, 18 Sep 2003 04:14:04 -0400
- Reply-to: or-dev@freehaven.net
- Sender: owner-or-cvs@freehaven.net
Update of /home/or/cvsroot/src/or
In directory moria.mit.edu:/home2/arma/work/onion/cvs/src/or
Modified Files:
buffers.c circuit.c connection.c connection_edge.c directory.c
main.c or.h routers.c
Log Message:
leave the socks handshake on the inbuf until it's complete
this paves the way for supporting socks5 and other handshakes
it also removes those pesky AP-only variables from connection_t
also hacked a fix for a bug where some streams weren't ending properly --
maybe because marked connections weren't flushing properly?
Index: buffers.c
===================================================================
RCS file: /home/or/cvsroot/src/or/buffers.c,v
retrieving revision 1.32
retrieving revision 1.33
diff -u -d -r1.32 -r1.33
--- buffers.c 17 Sep 2003 20:09:05 -0000 1.32
+++ buffers.c 18 Sep 2003 08:11:31 -0000 1.33
@@ -126,8 +126,8 @@
*buf_datalen -= write_result;
*buf_flushlen -= write_result;
memmove(*buf, *buf+write_result, *buf_datalen);
-// log_fn(LOG_DEBUG,"flushed %d bytes, %d ready to flush, %d remain.",
-// write_result,*buf_flushlen,*buf_datalen);
+ log_fn(LOG_DEBUG,"%d: flushed %d bytes, %d ready to flush, %d remain.",
+ s,write_result,*buf_flushlen,*buf_datalen);
return *buf_flushlen;
/* XXX USE_TLS should change to return write_result like any sane function would */
}
@@ -254,6 +254,86 @@
*buf_datalen -= (headerlen+bodylen);
memmove(buf, buf+headerlen+bodylen, *buf_datalen);
+ return 1;
+}
+
+/* There is a (possibly incomplete) socks handshake on *buf, of the
+ * forms
+ * socks4: "socksheader || username\0".
+ * socks4a: "socksheader || username\0 || destaddr\0".
+ * If it's a complete and valid handshake, and destaddr fits in addr_out,
+ * then pull the handshake off the buf, assign to addr_out and port_out,
+ * and return 1.
+ * If it's invalid or too big, return -1.
+ * Else it's not all there yet, change nothing return 0.
+ */
+int fetch_from_buf_socks(char *buf, int *buf_datalen,
+ char *addr_out, int max_addrlen,
+ uint16_t *port_out) {
+ socks4_t *socks4_info;
+ char tmpbuf[512];
+ uint16_t port;
+ enum {socks4, socks4a } socks_prot = socks4a;
+ char *next, *startaddr;
+
+ if(*buf_datalen < sizeof(socks4_t)) /* basic info available? */
+ return 0; /* not yet */
+
+ socks4_info = (socks4_t *)buf;
+
+ if(socks4_info->version != 4) {
+ log_fn(LOG_NOTICE,"Unrecognized version %d.",socks4_info->version);
+ return -1;
+ }
+
+ if(socks4_info->command != 1) { /* not a connect? we don't support it. */
+ log_fn(LOG_NOTICE,"command %d not '1'.",socks4_info->command);
+ return -1;
+ }
+
+ port = ntohs(*(uint16_t*)&socks4_info->destport);
+ if(!port) {
+ log_fn(LOG_NOTICE,"Port is zero.");
+ return -1;
+ }
+
+ if(socks4_info->destip[0] || socks4_info->destip[1] ||
+ socks4_info->destip[2] || !socks4_info->destip[3]) { /* not 0.0.0.x */
+ log_fn(LOG_NOTICE,"destip not in form 0.0.0.x.");
+ sprintf(tmpbuf, "%d.%d.%d.%d", socks4_info->destip[0],
+ socks4_info->destip[1], socks4_info->destip[2], socks4_info->destip[3]);
+ if(max_addrlen <= strlen(tmpbuf)) {
+ log_fn(LOG_DEBUG,"socks4-addr too long.");
+ return -1;
+ }
+ log_fn(LOG_DEBUG,"Successfully read destip (%s)", tmpbuf);
+ socks_prot = socks4;
+ }
+
+ next = memchr(buf+sizeof(socks4_t), 0, *buf_datalen);
+ if(!next) {
+ log_fn(LOG_DEBUG,"Username not here yet.");
+ return 0;
+ }
+
+ startaddr = next+1;
+ if(socks_prot == socks4a) {
+ next = memchr(startaddr, 0, buf+*buf_datalen-startaddr);
+ if(!next) {
+ log_fn(LOG_DEBUG,"Destaddr not here yet.");
+ return 0;
+ }
+ if(max_addrlen <= next-startaddr) {
+ log_fn(LOG_DEBUG,"Destaddr not here yet.");
+ return -1;
+ }
+ }
+ log_fn(LOG_DEBUG,"Everything is here. Success.");
+ *port_out = port;
+ strcpy(addr_out, socks_prot == socks4 ? tmpbuf : startaddr);
+ *buf_datalen -= (next-buf+1); /* next points to the final \0 on inbuf */
+ memmove(buf, next+1, *buf_datalen);
+// log_fn(LOG_DEBUG,"buf_datalen is now %d:'%s'",*buf_datalen,buf);
return 1;
}
Index: circuit.c
===================================================================
RCS file: /home/or/cvsroot/src/or/circuit.c,v
retrieving revision 1.65
retrieving revision 1.66
diff -u -d -r1.65 -r1.66
--- circuit.c 16 Sep 2003 20:57:08 -0000 1.65
+++ circuit.c 18 Sep 2003 08:11:31 -0000 1.66
@@ -807,8 +807,9 @@
return 0;
}
-/* take the 'extend' cell, pull out addr/port plus the onion skin. Connect
- * to the next hop, and pass it the onion skin in a create cell.
+/* take the 'extend' cell, pull out addr/port plus the onion skin. Make
+ * sure we're connected to the next hop, and pass it the onion skin in
+ * a create cell.
*/
int circuit_extend(cell_t *cell, circuit_t *circ) {
connection_t *n_conn;
Index: connection.c
===================================================================
RCS file: /home/or/cvsroot/src/or/connection.c,v
retrieving revision 1.98
retrieving revision 1.99
diff -u -d -r1.98 -r1.99
--- connection.c 17 Sep 2003 20:09:05 -0000 1.98
+++ connection.c 18 Sep 2003 08:11:31 -0000 1.99
@@ -98,8 +98,6 @@
buf_free(conn->outbuf);
if(conn->address)
free(conn->address);
- if(conn->dest_addr)
- free(conn->dest_addr);
if(connection_speaks_cells(conn)) {
directory_set_dirty();
@@ -527,13 +525,6 @@
return fetch_from_buf(string, len, &conn->inbuf, &conn->inbuflen, &conn->inbuf_datalen);
}
-int connection_fetch_from_buf_http(connection_t *conn,
- char *headers_out, int max_headerlen,
- char *body_out, int max_bodylen) {
- return fetch_from_buf_http(conn->inbuf,&conn->inbuf_datalen,
- headers_out, max_headerlen, body_out, max_bodylen);
-}
-
int connection_find_on_inbuf(char *string, int len, connection_t *conn) {
return find_on_inbuf(string, len, conn->inbuf, conn->inbuf_datalen);
}
@@ -780,13 +771,6 @@
assert(conn->cpath_layer);
assert_cpath_layer_ok(conn->cpath_layer);
/* XXX unchecked, package window, deliver window. */
- }
-
- if (conn->type != CONN_TYPE_AP) {
- assert(!conn->socks_version);
- assert(!conn->read_username);
- assert(!conn->dest_addr);
- assert(!conn->dest_port);
}
switch(conn->type)
Index: connection_edge.c
===================================================================
RCS file: /home/or/cvsroot/src/or/connection_edge.c,v
retrieving revision 1.22
retrieving revision 1.23
diff -u -d -r1.22 -r1.23
--- connection_edge.c 16 Sep 2003 20:57:08 -0000 1.22
+++ connection_edge.c 18 Sep 2003 08:11:31 -0000 1.23
@@ -7,7 +7,8 @@
extern or_options_t options; /* command-line and config-file options */
static int connection_ap_handshake_process_socks(connection_t *conn);
-static int connection_ap_handshake_send_begin(connection_t *ap_conn, circuit_t *circ);
+static int connection_ap_handshake_send_begin(connection_t *ap_conn, circuit_t *circ,
+ char *destaddr, uint16_t destport);
static int connection_ap_handshake_socks_reply(connection_t *conn, char result);
static int connection_exit_begin_conn(cell_t *cell, circuit_t *circ);
@@ -17,16 +18,6 @@
#define SOCKS4_REQUEST_IDENT_FAILED 92
#define SOCKS4_REQUEST_IDENT_CONFLICT 93
-/* structure of a socks client operation */
-typedef struct {
- unsigned char version; /* socks version number */
- unsigned char command; /* command code */
- unsigned char destport[2]; /* destination port, network order */
- unsigned char destip[4]; /* destination address */
- /* userid follows, terminated by a NULL */
- /* dest host follows, terminated by a NULL */
-} socks4_t;
-
int connection_edge_process_inbuf(connection_t *conn) {
assert(conn);
@@ -441,86 +432,24 @@
}
static int connection_ap_handshake_process_socks(connection_t *conn) {
- socks4_t socks4_info;
circuit_t *circ;
- char tmpbuf[512];
- int amt;
+ char destaddr[200];
+ uint16_t destport;
assert(conn);
log_fn(LOG_DEBUG,"entered.");
- if(!conn->socks_version) { /* try to pull it in */
-
- if(conn->inbuf_datalen < sizeof(socks4_t)) /* basic info available? */
- return 0; /* not yet */
-
- connection_fetch_from_buf((char *)&socks4_info,sizeof(socks4_t),conn);
-
- log_fn(LOG_DEBUG,"Successfully read socks info.");
-
- if(socks4_info.version != 4) {
- log_fn(LOG_NOTICE,"Unrecognized version %d.",socks4_info.version);
- connection_ap_handshake_socks_reply(conn, SOCKS4_REQUEST_REJECT);
- return -1;
- }
- conn->socks_version = socks4_info.version;
-
- if(socks4_info.command != 1) { /* not a connect? we don't support it. */
- log_fn(LOG_NOTICE,"command %d not '1'.",socks4_info.command);
- connection_ap_handshake_socks_reply(conn, SOCKS4_REQUEST_REJECT);
- return -1;
- }
-
- conn->dest_port = ntohs(*(uint16_t*)&socks4_info.destport);
- if(!conn->dest_port) {
- log_fn(LOG_NOTICE,"Port is zero.");
- connection_ap_handshake_socks_reply(conn, SOCKS4_REQUEST_REJECT);
- return -1;
- }
- log_fn(LOG_NOTICE,"Dest port is %d.",conn->dest_port);
-
- if(socks4_info.destip[0] ||
- socks4_info.destip[1] ||
- socks4_info.destip[2] ||
- !socks4_info.destip[3]) { /* not 0.0.0.x */
- log_fn(LOG_NOTICE,"destip not in form 0.0.0.x.");
- sprintf(tmpbuf, "%d.%d.%d.%d", socks4_info.destip[0],
- socks4_info.destip[1], socks4_info.destip[2], socks4_info.destip[3]);
- conn->dest_addr = strdup(tmpbuf);
- log_fn(LOG_DEBUG,"Successfully read destip (%s)", conn->dest_addr);
- }
-
- }
-
- if(!conn->read_username) { /* the socks spec says we've got to read stuff until we get a null */
- amt = connection_find_on_inbuf("\0", 1, conn);
- if(amt < 0) /* not there yet */
- return 0;
- if(amt > 500) {
- log_fn(LOG_NOTICE,"username too long.");
+ switch(fetch_from_buf_socks(conn->inbuf,&conn->inbuf_datalen,
+ destaddr, sizeof(destaddr), &destport)) {
+ case -1:
+ log_fn(LOG_DEBUG,"Fetching socks handshake failed. Closing.");
connection_ap_handshake_socks_reply(conn, SOCKS4_REQUEST_REJECT);
return -1;
- }
- connection_fetch_from_buf(tmpbuf,amt,conn);
- conn->read_username = 1;
- log_fn(LOG_DEBUG,"Successfully read username.");
- }
-
- if(!conn->dest_addr) { /* no dest_addr found yet */
- amt = connection_find_on_inbuf("\0", 1, conn);
- if(amt < 0) /* not there yet */
+ case 0:
+ log_fn(LOG_DEBUG,"Fetching socks handshake, not all here yet. Ignoring.");
return 0;
- if(amt > 500) {
- log_fn(LOG_NOTICE,"dest_addr too long.");
- connection_ap_handshake_socks_reply(conn, SOCKS4_REQUEST_REJECT);
- return -1;
- }
- connection_fetch_from_buf(tmpbuf,amt,conn);
-
- conn->dest_addr = strdup(tmpbuf);
- log_fn(LOG_NOTICE,"successfully read dest addr '%s'",
- conn->dest_addr);
+ /* case 1, fall through */
}
/* find the circuit that we should use, if there is one. */
@@ -542,7 +471,7 @@
assert(circ->cpath->prev->state == CPATH_STATE_OPEN);
conn->cpath_layer = circ->cpath->prev;
- if(connection_ap_handshake_send_begin(conn, circ) < 0) {
+ if(connection_ap_handshake_send_begin(conn, circ, destaddr, destport) < 0) {
circuit_close(circ);
return -1;
}
@@ -550,11 +479,12 @@
return 0;
}
-static int connection_ap_handshake_send_begin(connection_t *ap_conn, circuit_t *circ) {
+/* deliver the destaddr:destport in a relay cell */
+static int connection_ap_handshake_send_begin(connection_t *ap_conn, circuit_t *circ,
+ char *destaddr, uint16_t destport) {
cell_t cell;
-
memset(&cell, 0, sizeof(cell_t));
- /* deliver the dest_addr in a relay cell */
+
cell.command = CELL_RELAY;
cell.aci = circ->n_aci;
SET_CELL_RELAY_COMMAND(cell, RELAY_COMMAND_BEGIN);
@@ -566,7 +496,7 @@
memcpy(cell.payload+RELAY_HEADER_SIZE, ap_conn->stream_id, STREAM_ID_SIZE);
cell.length =
snprintf(cell.payload+RELAY_HEADER_SIZE+STREAM_ID_SIZE, CELL_PAYLOAD_SIZE-RELAY_HEADER_SIZE-STREAM_ID_SIZE,
- "%s:%d", ap_conn->dest_addr, ap_conn->dest_port) +
+ "%s:%d", destaddr, destport) +
1 + STREAM_ID_SIZE + RELAY_HEADER_SIZE;
log_fn(LOG_DEBUG,"Sending relay cell (id %d) to begin stream %d.", *(int *)(cell.payload+1),*(int *)ap_conn->stream_id);
if(circuit_deliver_relay_cell(&cell, circ, CELL_DIRECTION_OUT, ap_conn->cpath_layer) < 0) {
Index: directory.c
===================================================================
RCS file: /home/or/cvsroot/src/or/directory.c,v
retrieving revision 1.27
retrieving revision 1.28
diff -u -d -r1.27 -r1.28
--- directory.c 17 Sep 2003 20:09:05 -0000 1.27
+++ directory.c 18 Sep 2003 08:11:31 -0000 1.28
@@ -141,7 +141,8 @@
switch(conn->state) {
case DIR_CONN_STATE_CLIENT_READING_GET:
/* kill it, but first process the_directory and learn about new routers. */
- switch(connection_fetch_from_buf_http(conn, NULL, 0, the_directory, MAX_DIR_SIZE)) {
+ switch(fetch_from_buf_http(conn->inbuf,&conn->inbuf_datalen,
+ NULL, 0, the_directory, MAX_DIR_SIZE)) {
case -1: /* overflow */
log_fn(LOG_DEBUG,"'get' response too large. Failing.");
return -1;
@@ -191,7 +192,8 @@
assert(conn && conn->type == CONN_TYPE_DIR);
- switch(connection_fetch_from_buf_http(conn, headers, sizeof(headers), body, sizeof(body))) {
+ switch(fetch_from_buf_http(conn->inbuf,&conn->inbuf_datalen,
+ headers, sizeof(headers), body, sizeof(body))) {
case -1: /* overflow */
log_fn(LOG_DEBUG,"input too large. Failing.");
return -1;
Index: main.c
===================================================================
RCS file: /home/or/cvsroot/src/or/main.c,v
retrieving revision 1.96
retrieving revision 1.97
diff -u -d -r1.96 -r1.97
--- main.c 17 Sep 2003 20:09:05 -0000 1.96
+++ main.c 18 Sep 2003 08:11:31 -0000 1.97
@@ -301,9 +301,11 @@
assert(conn);
if(conn->marked_for_close) {
log_fn(LOG_DEBUG,"Cleaning up connection.");
- if(conn->s >= 0) { /* might be an incomplete exit connection */
+ if(conn->s >= 0) { /* might be an incomplete edge connection */
/* FIXME there's got to be a better way to check for this -- and make other checks? */
- connection_flush_buf(conn); /* flush it first */
+ connection_handle_write(conn); /* flush it first */
+ if(connection_wants_to_flush(conn)) /* not done flushing */
+ log_fn(LOG_WARNING,"Conn (socket %d) still wants to flush. Losing %d bytes!",conn->s, conn->inbuf_datalen);
}
connection_remove(conn);
connection_free(conn);
Index: or.h
===================================================================
RCS file: /home/or/cvsroot/src/or/or.h,v
retrieving revision 1.132
retrieving revision 1.133
diff -u -d -r1.132 -r1.133
--- or.h 17 Sep 2003 20:09:06 -0000 1.132
+++ or.h 18 Sep 2003 08:11:31 -0000 1.133
@@ -215,6 +215,16 @@
/* legal characters in a filename */
#define CONFIG_LEGAL_FILENAME_CHARACTERS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_/"
+/* structure of a socks client operation */
+typedef struct {
+ unsigned char version; /* socks version number */
+ unsigned char command; /* command code */
+ unsigned char destport[2]; /* destination port, network order */
+ unsigned char destip[4]; /* destination address */
+ /* userid follows, terminated by a NULL */
+ /* dest host follows, terminated by a NULL */
+} socks4_t;
+
typedef uint16_t aci_t;
/* cell definition */
@@ -293,12 +303,6 @@
int done_sending; /* for half-open connections; not used currently */
int done_receiving;
-
-/* Used only by AP connections: */
- char socks_version; /* what socks version are they speaking at me? */
- char read_username; /* have i read the username yet? */
- char *dest_addr; /* what address and port are this stream's destination? */
- uint16_t dest_port; /* host order */
};
typedef struct connection_t connection_t;
@@ -443,6 +447,9 @@
int fetch_from_buf_http(char *buf, int *buf_datalen,
char *headers_out, int max_headerlen,
char *body_out, int max_bodylen);
+int fetch_from_buf_socks(char *buf, int *buf_datalen,
+ char *addr_out, int max_addrlen,
+ uint16_t *port_out);
int find_on_inbuf(char *string, int string_len, char *buf, int buf_datalen);
/********************************* circuit.c ***************************/
@@ -510,9 +517,6 @@
int connection_read_to_buf(connection_t *conn);
int connection_fetch_from_buf(char *string, int len, connection_t *conn);
-int connection_fetch_from_buf_http(connection_t *conn,
- char *headers_out, int max_headerlen,
- char *body_out, int max_bodylen);
int connection_find_on_inbuf(char *string, int len, connection_t *conn);
int connection_wants_to_flush(connection_t *conn);
Index: routers.c
===================================================================
RCS file: /home/or/cvsroot/src/or/routers.c,v
retrieving revision 1.48
retrieving revision 1.49
diff -u -d -r1.48 -r1.49
--- routers.c 17 Sep 2003 20:09:06 -0000 1.48
+++ routers.c 18 Sep 2003 08:11:31 -0000 1.49
@@ -42,39 +42,35 @@
int learn_my_address(struct sockaddr_in *me) {
/* local host information */
char localhostname[512];
- static struct hostent *localhost;
+ struct hostent *localhost;
+ static struct sockaddr_in answer;
static int already_learned=0;
- if(already_learned) {
- memset(me,0,sizeof(struct sockaddr_in));
- me->sin_family = AF_INET;
- memcpy((void *)&me->sin_addr,(void *)localhost->h_addr,sizeof(struct in_addr));
- me->sin_port = htons((uint16_t) options.ORPort);
- return 0;
- }
-
- /* obtain local host information */
- if(gethostname(localhostname,512) < 0) {
- log_fn(LOG_ERR,"Error obtaining local hostname");
- return -1;
- }
- log_fn(LOG_DEBUG,"localhostname is '%s'.",localhostname);
- localhost = gethostbyname(localhostname);
- if (!localhost) {
- log_fn(LOG_ERR,"Error obtaining local host info.");
- return -1;
- }
- memset(me,0,sizeof(struct sockaddr_in));
- me->sin_family = AF_INET;
- memcpy((void *)&me->sin_addr,(void *)localhost->h_addr,sizeof(struct in_addr));
- me->sin_port = htons((uint16_t) options.ORPort);
- log_fn(LOG_DEBUG,"chose address as '%s'.",inet_ntoa(me->sin_addr));
- if (!strncmp("127.",inet_ntoa(me->sin_addr), 4) &&
- strcasecmp(localhostname, "localhost")) {
- /* We're a loopback IP but we're not called localhost. Uh oh! */
- log_fn(LOG_WARNING, "Got a loopback address: /etc/hosts may be wrong");
+ if(!already_learned) {
+ /* obtain local host information */
+ if(gethostname(localhostname,512) < 0) {
+ log_fn(LOG_ERR,"Error obtaining local hostname");
+ return -1;
+ }
+ log_fn(LOG_DEBUG,"localhostname is '%s'.",localhostname);
+ localhost = gethostbyname(localhostname);
+ if (!localhost) {
+ log_fn(LOG_ERR,"Error obtaining local host info.");
+ return -1;
+ }
+ memset(&answer,0,sizeof(struct sockaddr_in));
+ answer.sin_family = AF_INET;
+ memcpy((void *)&answer.sin_addr,(void *)localhost->h_addr,sizeof(struct in_addr));
+ answer.sin_port = htons((uint16_t) options.ORPort);
+ log_fn(LOG_DEBUG,"chose address as '%s'.",inet_ntoa(answer.sin_addr));
+ if (!strncmp("127.",inet_ntoa(answer.sin_addr), 4) &&
+ strcasecmp(localhostname, "localhost")) {
+ /* We're a loopback IP but we're not called localhost. Uh oh! */
+ log_fn(LOG_WARNING, "Got a loopback address: /etc/hosts may be wrong");
+ }
+ already_learned = 1;
}
- already_learned=1;
+ memcpy(me,&answer,sizeof(struct sockaddr_in));
return 0;
}