[or-cvs] Re-do fragmented control message handling to work with new ...

Nick Mathewson nickm at seul.org
Wed Apr 27 22:01:37 UTC 2005


Update of /home/or/cvsroot/tor/src/or
In directory moria.mit.edu:/tmp/cvs-serv14858/src/or

Modified Files:
	buffers.c connection.c control.c or.h 
Log Message:
Re-do fragmented control message handling to work with new buf_t system.

Index: buffers.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/buffers.c,v
retrieving revision 1.143
retrieving revision 1.144
diff -u -d -r1.143 -r1.144
--- buffers.c	27 Apr 2005 20:02:52 -0000	1.143
+++ buffers.c	27 Apr 2005 22:01:34 -0000	1.144
@@ -968,7 +968,7 @@
 {
   uint32_t msglen;
   uint16_t type;
-  char tmp[10];
+  char tmp[4];
 
   tor_assert(buf);
   tor_assert(len_out);
@@ -985,77 +985,17 @@
     return 0;
 
   type = ntohs(get_uint16(tmp+2));
-  if (type != CONTROL_CMD_FRAGMENTHEADER) {
-    *len_out = msglen;
-    *type_out = type;
-    buf_remove_from_front(buf, 4);
-    if (msglen) {
-      *body_out = tor_malloc(msglen+1);
-      fetch_from_buf(*body_out, msglen, buf);
-      (*body_out)[msglen] = '\0';
-    } else {
-      *body_out = NULL;
-    }
-    return 1;
+  *len_out = msglen;
+  *type_out = type;
+  buf_remove_from_front(buf, 4);
+  if (msglen) {
+    *body_out = tor_malloc(msglen+1);
+    fetch_from_buf(*body_out, msglen, buf);
+    (*body_out)[msglen] = '\0';
   } else {
-    uint32_t totallen, sofar;
-    char *cp, *endp, *outp;
-
-    /* Okay, we have a fragmented message.  Is it all here? */
-    if (msglen < 6)
-      return -1;
-    peek_from_buf(tmp, 10, buf);
-    type = htons(get_uint16(tmp+4));
-    totallen = htonl(get_uint32(tmp+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->cur+4+msglen;
-    endp = buf->cur+buf->datalen;
-    /* XXXXX!!!!!! This will not handle fragmented messages right now. */
-    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) < (int)(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;
+    *body_out = NULL;
   }
+  return 1;
 }
 
 /** Log an error and exit if <b>buf</b> is corrupted.

Index: connection.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/connection.c,v
retrieving revision 1.365
retrieving revision 1.366
diff -u -d -r1.365 -r1.366
--- connection.c	26 Apr 2005 20:55:32 -0000	1.365
+++ connection.c	27 Apr 2005 22:01:34 -0000	1.366
@@ -209,6 +209,7 @@
     crypto_free_pk_env(conn->identity_pkey);
   tor_free(conn->nickname);
   tor_free(conn->socks_request);
+  tor_free(conn->incoming_cmd);
   tor_free(conn->read_event); /* Probably already freed by connection_free. */
   tor_free(conn->write_event); /* Probably already freed by connection_free. */
 

Index: control.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/control.c,v
retrieving revision 1.78
retrieving revision 1.79
diff -u -d -r1.78 -r1.79
--- control.c	17 Apr 2005 22:52:02 -0000	1.78
+++ control.c	27 Apr 2005 22:01:34 -0000	1.79
@@ -923,6 +923,46 @@
   return 0;
 }
 
+static int
+handle_control_fragments(connection_t *conn, uint16_t command_type,
+                         uint32_t body_len, char *body)
+{
+  if (command_type == CONTROL_CMD_FRAGMENTHEADER) {
+    if (conn->incoming_cmd) {
+      log_fn(LOG_WARN, "Dropping incomplete fragmented command");
+      tor_free(conn->incoming_cmd);
+    }
+    if (body_len < 6) {
+      send_control_error(conn, ERR_SYNTAX, "FRAGMENTHEADER too short.");
+      return 0;
+    }
+    conn->incoming_cmd_type = ntohs(get_uint16(body));
+    conn->incoming_cmd_len = ntohl(get_uint32(body+2));
+    conn->incoming_cmd_cur_len = 0;
+    conn->incoming_cmd = tor_malloc(conn->incoming_cmd_len);
+    body += 6;
+    body_len -= 6;
+  } else if (command_type == CONTROL_CMD_FRAGMENT) {
+    if (!conn->incoming_cmd) {
+      send_control_error(conn, ERR_SYNTAX, "Out-of-place FRAGMENT");
+      return 0;
+    }
+  } else {
+    tor_assert(0);
+  }
+
+  if (conn->incoming_cmd_cur_len + body_len > conn->incoming_cmd_len) {
+    tor_free(conn->incoming_cmd);
+    send_control_error(conn, ERR_SYNTAX,
+                       "Fragmented data exceeds declared length");
+    return 0;
+  }
+  memcpy(conn->incoming_cmd + conn->incoming_cmd_cur_len,
+         body, body_len);
+  conn->incoming_cmd_cur_len += body_len;
+  return 0;
+}
+
 /** Called when <b>conn</b> has no more bytes left on its outbuf. */
 int
 connection_control_finished_flushing(connection_t *conn) {
@@ -980,6 +1020,23 @@
     goto again;
   }
 
+  if (command_type == CONTROL_CMD_FRAGMENTHEADER ||
+      command_type == CONTROL_CMD_FRAGMENT) {
+    if (handle_control_fragments(conn, command_type, body_len, body))
+      return -1;
+    tor_free(body);
+    if (conn->incoming_cmd_cur_len != conn->incoming_cmd_len)
+      goto again;
+
+    command_type = conn->incoming_cmd_type;
+    body_len = conn->incoming_cmd_len;
+    body = conn->incoming_cmd;
+    conn->incoming_cmd = NULL;
+  } else if (conn->incoming_cmd) {
+    log_fn(LOG_WARN, "Dropping incomplete fragmented command");
+    tor_free(conn->incoming_cmd);
+  }
+
   /* Okay, we're willing to process the command. */
   switch (command_type)
     {

Index: or.h
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/or.h,v
retrieving revision 1.596
retrieving revision 1.597
diff -u -d -r1.596 -r1.597
--- or.h	26 Apr 2005 18:52:16 -0000	1.596
+++ or.h	27 Apr 2005 22:01:34 -0000	1.597
@@ -639,6 +639,10 @@
 
   /* Used only by control connections */
   uint32_t event_mask;
+  uint16_t incoming_cmd_type;
+  uint32_t incoming_cmd_len;
+  uint32_t incoming_cmd_cur_len;
+  char *incoming_cmd;
 };
 
 typedef struct connection_t connection_t;



More information about the tor-commits mailing list