mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2025-02-22 14:23:04 +01:00
Re-do fragmented control message handling to work with new buf_t system.
svn:r4144
This commit is contained in:
parent
02546857d2
commit
fe65e57ca1
4 changed files with 72 additions and 70 deletions
|
@ -968,7 +968,7 @@ int fetch_from_buf_control(buf_t *buf, uint32_t *len_out, uint16_t *type_out,
|
|||
{
|
||||
uint32_t msglen;
|
||||
uint16_t type;
|
||||
char tmp[10];
|
||||
char tmp[4];
|
||||
|
||||
tor_assert(buf);
|
||||
tor_assert(len_out);
|
||||
|
@ -985,77 +985,17 @@ int fetch_from_buf_control(buf_t *buf, uint32_t *len_out, uint16_t *type_out,
|
|||
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.
|
||||
|
|
|
@ -209,6 +209,7 @@ _connection_free(connection_t *conn) {
|
|||
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. */
|
||||
|
||||
|
|
|
@ -923,6 +923,46 @@ handle_control_closecircuit(connection_t *conn, uint32_t len,
|
|||
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 @@ connection_control_process_inbuf(connection_t *conn) {
|
|||
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)
|
||||
{
|
||||
|
|
|
@ -639,6 +639,10 @@ struct connection_t {
|
|||
|
||||
/* 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;
|
||||
|
|
Loading…
Add table
Reference in a new issue