[or-cvs] Specify and implement fragmented control messages to allow ...
Nick Mathewson
nickm at seul.org
Wed Mar 2 20:22:14 UTC 2005
Update of /home/or/cvsroot/tor/src/or
In directory moria.mit.edu:/tmp/cvs-serv27764/src/or
Modified Files:
buffers.c control.c or.h
Log Message:
Specify and implement fragmented control messages to allow for (among other things) long GETINFO replies. Otherwise we could hit the 64K barrier on questions like "please dump your client-side DNS cache."
Index: buffers.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/buffers.c,v
retrieving revision 1.127
retrieving revision 1.128
diff -u -d -r1.127 -r1.128
--- buffers.c 1 Mar 2005 22:16:15 -0000 1.127
+++ buffers.c 2 Mar 2005 20:22:10 -0000 1.128
@@ -645,20 +645,24 @@
}
}
+
+#define CONTROL_CMD_FRAGMENTHEADER 0x0010
+#define CONTROL_CMD_FRAGMENT 0x0011
/** If there is a complete control message waiting on buf, then store
* its contents into *<b>type_out</b>, store its body's length into
* *<b>len_out</b>, allocate and store a string for its body into
- * *<b>body_out</b>, and return -1. (body_out will always be NUL-terminated,
+ * *<b>body_out</b>, and return 1. (body_out will always be NUL-terminated,
* even if the control message body doesn't end with NUL.)
*
* If there is not a complete control message waiting, return 0.
*
* Return -1 on error.
*/
-int fetch_from_buf_control(buf_t *buf, uint16_t *len_out, uint16_t *type_out,
+int fetch_from_buf_control(buf_t *buf, uint32_t *len_out, uint16_t *type_out,
char **body_out)
{
- uint16_t len;
+ uint32_t msglen;
+ uint16_t type;
tor_assert(buf);
tor_assert(len_out);
@@ -668,23 +672,82 @@
if (buf->datalen < 4)
return 0;
- len = ntohs(get_uint16(buf->mem));
- if (buf->datalen < 4 + (unsigned)len)
+ msglen = ntohs(get_uint16(buf->mem));
+ if (buf->datalen < 4 + (unsigned)msglen)
return 0;
- *len_out = len;
- *type_out = ntohs(get_uint16(buf->mem+2));
- if (len) {
- *body_out = tor_malloc(len+1);
- memcpy(*body_out, buf->mem+4, len);
- (*body_out)[len] = '\0';
+ type = ntohs(get_uint16(buf->mem+2));
+ if (type != CONTROL_CMD_FRAGMENTHEADER) {
+ *len_out = msglen;
+ *type_out = type;
+ if (msglen) {
+ *body_out = tor_malloc(msglen+1);
+ memcpy(*body_out, buf->mem+4, msglen);
+ (*body_out)[msglen] = '\0';
+ } else {
+ *body_out = NULL;
+ }
+ buf_remove_from_front(buf, 4+msglen);
+
+ return 1;
} else {
- *body_out = NULL;
- }
+ uint32_t totallen, sofar;
+ char *cp, *endp, *outp;
- buf_remove_from_front(buf, 4+len);
+ /* Okay, we have a fragmented message. Is it all here? */
+ if (msglen < 6)
+ return -1;
+ type = htons(get_uint16(buf->mem+4));
+ totallen = htonl(get_uint32(buf->mem+6));
+ if (totallen < 65536)
+ return -1;
+
+ if (buf->datalen<4+6+totallen)
+ /* The data can't possibly be here yet, no matter how well it's packed.*/
+ return 0;
+
+ /* Count how much data is really here. */
+ sofar = msglen-6;
+ cp = buf->mem+4+msglen;
+ endp = buf->mem+buf->datalen;
+ while (sofar < totallen) {
+ if ((endp-cp)<4)
+ return 0; /* Fragment header not all here. */
+ msglen = ntohs(get_uint16(cp));
+ if (ntohs(get_uint16(cp+2) != CONTROL_CMD_FRAGMENT))
+ return -1; /* Missing fragment message; error. */
+ if ((endp-cp) < 4+msglen)
+ return 0; /* Fragment not all here. */
+ sofar += msglen;
+ cp += (4+msglen);
+ }
+ if (sofar > totallen)
+ return -1; /* Fragments add to more than expected; error. */
+
+ /* Okay, everything is here. */
+ *len_out = totallen;
+ *type_out = type;
+ *body_out = tor_malloc(totallen+1);
+
+ /* copy FRAGMENTED packet contents. */
+ msglen = ntohs(get_uint16(buf->mem));
+ if (msglen>6)
+ memcpy(*body_out,buf->mem+4+6,msglen-6);
+ sofar = msglen-6;
+ outp = *body_out+sofar;
+ cp = buf->mem+4+msglen;
+ while (sofar < totallen) {
+ msglen = ntohs(get_uint16(cp));
+ memcpy(outp,cp+4,msglen);
+ outp += msglen;
+ cp += 4+msglen;
+ sofar -= msglen;
+ }
+ (*body_out)[totallen]='\0';
+
+ return 1;
+ }
- return 1;
}
/** Log an error and exit if <b>buf</b> is corrupted.
Index: control.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/control.c,v
retrieving revision 1.47
retrieving revision 1.48
diff -u -d -r1.47 -r1.48
--- control.c 2 Mar 2005 19:26:46 -0000 1.47
+++ control.c 2 Mar 2005 20:22:10 -0000 1.48
@@ -46,7 +46,9 @@
#define CONTROL_CMD_EXTENDCIRCUIT 0x000D
#define CONTROL_CMD_ATTACHSTREAM 0x000E
#define CONTROL_CMD_POSTDESCRIPTOR 0x000F
-#define _CONTROL_CMD_MAX_RECOGNIZED 0x000F
+#define CONTROL_CMD_FRAGMENTHEADER 0x0010
+#define CONTROL_CMD_FRAGMENT 0x0011
+#define _CONTROL_CMD_MAX_RECOGNIZED 0x0011
/* Recognized error codes. */
#define ERR_UNSPECIFIED 0x0000
@@ -89,7 +91,9 @@
"infovalue",
"extendcircuit",
"attachstream",
- "postdescriptor"
+ "postdescriptor",
+ "fragmentheader",
+ "fragment",
};
/** Bitfield: The bit 1<<e is set if <b>any</b> open control
@@ -115,33 +119,33 @@
static void update_global_event_mask(void);
static void send_control_message(connection_t *conn, uint16_t type,
- uint16_t len, const char *body);
+ uint32_t len, const char *body);
static void send_control_done(connection_t *conn);
static void send_control_done2(connection_t *conn, const char *msg, size_t len);
static void send_control_error(connection_t *conn, uint16_t error,
const char *message);
-static void send_control_event(uint16_t event, uint16_t len, const char *body);
-static int handle_control_setconf(connection_t *conn, uint16_t len,
+static void send_control_event(uint16_t event, uint32_t len, const char *body);
+static int handle_control_setconf(connection_t *conn, uint32_t len,
char *body);
-static int handle_control_getconf(connection_t *conn, uint16_t len,
+static int handle_control_getconf(connection_t *conn, uint32_t len,
const char *body);
-static int handle_control_setevents(connection_t *conn, uint16_t len,
+static int handle_control_setevents(connection_t *conn, uint32_t len,
const char *body);
-static int handle_control_authenticate(connection_t *conn, uint16_t len,
+static int handle_control_authenticate(connection_t *conn, uint32_t len,
const char *body);
-static int handle_control_saveconf(connection_t *conn, uint16_t len,
+static int handle_control_saveconf(connection_t *conn, uint32_t len,
const char *body);
-static int handle_control_signal(connection_t *conn, uint16_t len,
+static int handle_control_signal(connection_t *conn, uint32_t len,
const char *body);
-static int handle_control_mapaddress(connection_t *conn, uint16_t len,
+static int handle_control_mapaddress(connection_t *conn, uint32_t len,
const char *body);
-static int handle_control_getinfo(connection_t *conn, uint16_t len,
+static int handle_control_getinfo(connection_t *conn, uint32_t len,
const char *body);
-static int handle_control_extendcircuit(connection_t *conn, uint16_t len,
+static int handle_control_extendcircuit(connection_t *conn, uint32_t len,
const char *body);
-static int handle_control_attachstream(connection_t *conn, uint16_t len,
+static int handle_control_attachstream(connection_t *conn, uint32_t len,
const char *body);
-static int handle_control_postdescriptor(connection_t *conn, uint16_t len,
+static int handle_control_postdescriptor(connection_t *conn, uint32_t len,
const char *body);
/** Given a possibly invalid message type code <b>cmd</b>, return a
@@ -172,18 +176,38 @@
/** Send a message of type <b>type</b> containing <b>len</b> bytes
* from <b>body</b> along the control connection <b>conn</b> */
static void
-send_control_message(connection_t *conn, uint16_t type, uint16_t len,
+send_control_message(connection_t *conn, uint16_t type, uint32_t len,
const char *body)
{
- char buf[4];
+ char buf[10];
tor_assert(conn);
tor_assert(len || !body);
tor_assert(type <= _CONTROL_CMD_MAX_RECOGNIZED);
- set_uint16(buf, htons(len));
- set_uint16(buf+2, htons(type));
- connection_write_to_buf(buf, 4, conn);
- if (len)
- connection_write_to_buf(body, len, conn);
+ if (len < 65536) {
+ set_uint16(buf, htons(len));
+ set_uint16(buf+2, htons(type));
+ connection_write_to_buf(buf, 4, conn);
+ if (len)
+ connection_write_to_buf(body, len, conn);
+ } else {
+ set_uint16(buf, htons(65535));
+ set_uint16(buf+2, htons(CONTROL_CMD_FRAGMENTHEADER));
+ set_uint16(buf+4, htons(type));
+ set_uint32(buf+6, htonl(len));
+ connection_write_to_buf(buf, 10, conn);
+ connection_write_to_buf(body, 65535-6, conn);
+ len -= (65535-6);
+ body += (65535-6);
+ while (len) {
+ size_t chunklen = (len<65535)?len:65535;
+ set_uint16(buf, htons((uint16_t)chunklen));
+ set_uint16(buf+2, htons(CONTROL_CMD_FRAGMENT));
+ connection_write_to_buf(buf, 4, conn);
+ connection_write_to_buf(body, chunklen, conn);
+ len -= chunklen;
+ body += chunklen;
+ }
+ }
}
/** Send a "DONE" message down the control connection <b>conn</b> */
@@ -216,7 +240,7 @@
* <b>len</b> bytes in <b>body</b> to every control connection that
* is interested in it. */
static void
-send_control_event(uint16_t event, uint16_t len, const char *body)
+send_control_event(uint16_t event, uint32_t len, const char *body)
{
connection_t **conns;
int n_conns, i;
@@ -233,7 +257,7 @@
if (conns[i]->type == CONN_TYPE_CONTROL &&
conns[i]->state == CONTROL_CONN_STATE_OPEN &&
conns[i]->event_mask & (1<<event)) {
- send_control_message(conns[i], CONTROL_CMD_EVENT, (uint16_t)(buflen), buf);
+ send_control_message(conns[i], CONTROL_CMD_EVENT, buflen, buf);
}
}
@@ -243,7 +267,7 @@
/** Called when we receive a SETCONF message: parse the body and try
* to update our configuration. Reply with a DONE or ERROR message. */
static int
-handle_control_setconf(connection_t *conn, uint16_t len, char *body)
+handle_control_setconf(connection_t *conn, uint32_t len, char *body)
{
int r;
struct config_line_t *lines=NULL;
@@ -278,7 +302,7 @@
/** Called when we receive a GETCONF message. Parse the request, and
* reply with a CONFVALUE or an ERROR message */
static int
-handle_control_getconf(connection_t *conn, uint16_t body_len, const char *body)
+handle_control_getconf(connection_t *conn, uint32_t body_len, const char *body)
{
smartlist_t *questions = NULL;
smartlist_t *answers = NULL;
@@ -332,7 +356,7 @@
/** Called when we get a SETEVENTS message: update conn->event_mask,
* and reply with DONE or ERROR. */
static int
-handle_control_setevents(connection_t *conn, uint16_t len, const char *body)
+handle_control_setevents(connection_t *conn, uint32_t len, const char *body)
{
uint16_t event_code;
uint32_t event_mask = 0;
@@ -382,7 +406,7 @@
* OPEN. Reply with DONE or ERROR.
*/
static int
-handle_control_authenticate(connection_t *conn, uint16_t len, const char *body)
+handle_control_authenticate(connection_t *conn, uint32_t len, const char *body)
{
or_options_t *options = get_options();
if (options->CookieAuthentication) {
@@ -421,7 +445,7 @@
}
static int
-handle_control_saveconf(connection_t *conn, uint16_t len,
+handle_control_saveconf(connection_t *conn, uint32_t len,
const char *body)
{
if (save_current_config()<0) {
@@ -434,7 +458,7 @@
}
static int
-handle_control_signal(connection_t *conn, uint16_t len,
+handle_control_signal(connection_t *conn, uint32_t len,
const char *body)
{
if (len != 1) {
@@ -449,7 +473,7 @@
}
static int
-handle_control_mapaddress(connection_t *conn, uint16_t len, const char *body)
+handle_control_mapaddress(connection_t *conn, uint32_t len, const char *body)
{
smartlist_t *elts;
smartlist_t *lines;
@@ -478,8 +502,9 @@
log_fn(LOG_WARN,
"Unable to allocate address for '%s' in AdressMap msg", line);
} else {
- char *ans = tor_malloc(strlen(addr)+strlen(to)+2);
- tor_snprintf(ans, "%s %s", addr, to);
+ size_t anslen = strlen(addr)+strlen(to)+2;
+ char *ans = tor_malloc(anslen);
+ tor_snprintf(ans, anslen, "%s %s", addr, to);
addressmap_register(addr, tor_strdup(to), 0);
smartlist_add(reply, ans);
}
@@ -542,7 +567,7 @@
}
static int
-handle_control_getinfo(connection_t *conn, uint16_t len, const char *body)
+handle_control_getinfo(connection_t *conn, uint32_t len, const char *body)
{
smartlist_t *questions = NULL;
smartlist_t *answers = NULL;
@@ -574,7 +599,7 @@
msg = smartlist_join_strings2(answers, "\0", 1, 1, &msg_len);
send_control_message(conn, CONTROL_CMD_INFOVALUE,
- (uint16_t)msg_len, msg_len?msg:NULL);
+ msg_len, msg_len?msg:NULL);
done:
if (answers) SMARTLIST_FOREACH(answers, char *, cp, tor_free(cp));
@@ -586,20 +611,20 @@
return 0;
}
static int
-handle_control_extendcircuit(connection_t *conn, uint16_t len,
+handle_control_extendcircuit(connection_t *conn, uint32_t len,
const char *body)
{
send_control_error(conn,ERR_UNRECOGNIZED_TYPE,"not yet implemented");
return 0;
}
-static int handle_control_attachstream(connection_t *conn, uint16_t len,
+static int handle_control_attachstream(connection_t *conn, uint32_t len,
const char *body)
{
send_control_error(conn,ERR_UNRECOGNIZED_TYPE,"not yet implemented");
return 0;
}
static int
-handle_control_postdescriptor(connection_t *conn, uint16_t len,
+handle_control_postdescriptor(connection_t *conn, uint32_t len,
const char *body)
{
if (router_load_single_router(body)<0) {
@@ -634,7 +659,8 @@
*/
int
connection_control_process_inbuf(connection_t *conn) {
- uint16_t body_len, command_type;
+ uint32_t body_len;
+ uint16_t command_type;
char *body;
tor_assert(conn);
@@ -726,6 +752,10 @@
send_control_error(conn, ERR_UNRECOGNIZED_TYPE,
"Command type only valid from server to tor client");
break;
+ case CONTROL_CMD_FRAGMENTHEADER:
+ case CONTROL_CMD_FRAGMENT:
+ log_fn(LOG_WARN, "Recieved command fragment out of order; ignoring.");
+ send_control_error(conn, ERR_SYNTAX, "Bad fragmentation on command.");
default:
log_fn(LOG_WARN, "Received unrecognized command type %d; ignoring.",
(int)command_type);
@@ -756,7 +786,7 @@
set_uint32(msg+1, htonl(circ->global_identifier));
strlcpy(msg+5,path,path_len+1);
- send_control_event(EVENT_CIRCUIT_STATUS, (uint16_t)(path_len+6), msg);
+ send_control_event(EVENT_CIRCUIT_STATUS, (uint32_t)(path_len+6), msg);
tor_free(path);
tor_free(msg);
return 0;
@@ -784,7 +814,7 @@
set_uint32(msg+1, htonl(conn->global_identifier));
strlcpy(msg+5, buf, len+1);
- send_control_event(EVENT_STREAM_STATUS, (uint16_t)(5+len+1), msg);
+ send_control_event(EVENT_STREAM_STATUS, (uint32_t)(5+len+1), msg);
tor_free(msg);
return 0;
}
@@ -805,7 +835,7 @@
buf[0] = (uint8_t)tp;
strlcpy(buf+1,conn->nickname,sizeof(buf)-1);
len = strlen(buf+1);
- send_control_event(EVENT_OR_CONN_STATUS, (uint16_t)(len+1), buf);
+ send_control_event(EVENT_OR_CONN_STATUS, (uint32_t)(len+1), buf);
return 0;
}
@@ -837,7 +867,7 @@
return;
len = strlen(msg);
- send_control_event(EVENT_WARNING, (uint16_t)(len+1), msg);
+ send_control_event(EVENT_WARNING, (uint32_t)(len+1), msg);
}
/** Choose a random authentication cookie and write it to disk.
Index: or.h
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/or.h,v
retrieving revision 1.548
retrieving revision 1.549
diff -u -d -r1.548 -r1.549
--- or.h 2 Mar 2005 19:26:46 -0000 1.548
+++ or.h 2 Mar 2005 20:22:10 -0000 1.549
@@ -1100,7 +1100,7 @@
char **headers_out, size_t max_headerlen,
char **body_out, size_t *body_used, size_t max_bodylen);
int fetch_from_buf_socks(buf_t *buf, socks_request_t *req);
-int fetch_from_buf_control(buf_t *buf, uint16_t *len_out, uint16_t *type_out,
+int fetch_from_buf_control(buf_t *buf, uint32_t *len_out, uint16_t *type_out,
char **body_out);
void assert_buf_ok(buf_t *buf);
More information about the tor-commits
mailing list