diff --git a/src/or/buffers.c b/src/or/buffers.c index 6ce9c6ac1..33118c2b4 100644 --- a/src/or/buffers.c +++ b/src/or/buffers.c @@ -1228,54 +1228,20 @@ fetch_from_buf_socks(buf_t *buf, socks_request_t *req, } } -/** If there is a complete version 0 control message waiting on buf, then store - * its contents into *type_out, store its body's length into - * *len_out, allocate and store a string for its body into - * *body_out, 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; return -2 on "seems to be control protocol v1." - */ +/** Return 1 iff buf looks more like it has an (obsolete) v0 controller + * command on it than any valid v1 controller command. */ int -fetch_from_buf_control0(buf_t *buf, uint32_t *len_out, uint16_t *type_out, - char **body_out, int check_for_v1) +peek_buf_has_control0_command(buf_t *buf) { - uint32_t msglen; - uint16_t type; - char tmp[4]; - - tor_assert(buf); - tor_assert(len_out); - tor_assert(type_out); - tor_assert(body_out); - - *len_out = 0; - *body_out = NULL; - - if (buf->datalen < 4) - return 0; - - peek_from_buf(tmp, 4, buf); - - msglen = ntohs(get_uint16(tmp)); - type = ntohs(get_uint16(tmp+2)); - if (type > 255 && check_for_v1) - return -2; - - if (buf->datalen < 4 + (unsigned)msglen) - return 0; - - *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'; + if (buf->datalen >= 4) { + char header[4]; + uint16_t cmd; + peek_from_buf(header, sizeof(header), buf); + cmd = ntohs(get_uint16(header+2)); + if (cmd <= 0x14) + return 1; /* This is definitely not a v1 control command. */ } - return 1; + return 0; } /** Helper: return a pointer to the first instance of c in the diff --git a/src/or/control.c b/src/or/control.c index 521b810a8..80ea17bed 100644 --- a/src/or/control.c +++ b/src/or/control.c @@ -19,23 +19,6 @@ const char control_c_id[] = * See control-spec.txt for full details on protocol. */ -#if 0 -/* Recognized version 0 error codes. Do not expand. */ -#define ERR_UNSPECIFIED 0x0000 -#define ERR_INTERNAL 0x0001 -#define ERR_UNRECOGNIZED_TYPE 0x0002 -#define ERR_SYNTAX 0x0003 -#define ERR_UNRECOGNIZED_CONFIG_KEY 0x0004 -#define ERR_INVALID_CONFIG_VALUE 0x0005 -#define ERR_UNRECOGNIZED_EVENT_CODE 0x0006 -#define ERR_UNAUTHORIZED 0x0007 -#define ERR_REJECTED_AUTHENTICATION 0x0008 -#define ERR_RESOURCE_EXHAUSTED 0x0009 -#define ERR_NO_STREAM 0x000A -#define ERR_NO_CIRC 0x000B -#define ERR_NO_ROUTER 0x000C -#endif - /* Recognized asynchronous event types. It's okay to expand this list * because it is used both as a list of v0 event types, and as indices * into the bitfield to determine which controllers want which events. @@ -2267,6 +2250,24 @@ connection_control_process_inbuf(control_connection_t *conn) conn->incoming_cmd_cur_len = 0; } + if (conn->_base.state == CONTROL_CONN_STATE_NEEDAUTH_V1 && + peek_buf_has_control0_command(conn->_base.inbuf)) { + /* Detect v0 commands and send a "no more v0" message. */ + size_t body_len; + char buf[128]; + set_uint16(buf+2, htons(0x0000)); /* type == error */ + set_uint16(buf+4, htons(0x0001)); /* code == internal error */ + strlcpy(buf+6, "The v0 control protocol is not supported by Tor 0.2.0.x " + "and later; use Tor 0.1.2.x or upgrade your controller", + sizeof(buf)-6); + body_len = 2+strlen(buf+6)+2; /* code, msg, nul. */ + set_uint16(buf+0, htons(body_len)); + connection_write_to_buf(buf, 4+body_len, TO_CONN(conn)); + connection_mark_for_close(TO_CONN(conn)); + conn->_base.hold_open_until_flushed = 1; + return 0; + } + again: while (1) { size_t last_idx; diff --git a/src/or/or.h b/src/or/or.h index 7b5fd6bd5..b05458f4e 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -1923,8 +1923,7 @@ int fetch_from_buf_http(buf_t *buf, int force_complete); int fetch_from_buf_socks(buf_t *buf, socks_request_t *req, int log_sockstype, int safe_socks); -int fetch_from_buf_control0(buf_t *buf, uint32_t *len_out, uint16_t *type_out, - char **body_out, int check_for_v1); +int peek_buf_has_control0_command(buf_t *buf); int fetch_from_buf_line(buf_t *buf, char *data_out, size_t *data_len); int fetch_from_buf_line_lf(buf_t *buf, char *data_out, size_t *data_len);