summaryrefslogtreecommitdiff
path: root/src/or/control.c
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2005-06-19 20:40:41 +0000
committerNick Mathewson <nickm@torproject.org>2005-06-19 20:40:41 +0000
commit64fc1f7bae174d62c40686ec00674d2671c88258 (patch)
tree6d1a156e462c22f2fd5da207e95c06509c02f347 /src/or/control.c
parentb5fd75a063e487e845c98530cd2032f303d34462 (diff)
downloadtor-64fc1f7bae174d62c40686ec00674d2671c88258.tar.gz
tor-64fc1f7bae174d62c40686ec00674d2671c88258.zip
Implement all the rest of the new controller protocol, debug a little, add some new features, add ADDRMAP events.
svn:r4460
Diffstat (limited to 'src/or/control.c')
-rw-r--r--src/or/control.c355
1 files changed, 255 insertions, 100 deletions
diff --git a/src/or/control.c b/src/or/control.c
index 7fc5136e62..e584c68e79 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -71,7 +71,8 @@ const char control_c_id[] = "$Id$";
#define EVENT_NOTICE_MSG 0x0009
#define EVENT_WARN_MSG 0x000A
#define EVENT_ERR_MSG 0x000B
-#define _EVENT_MAX 0x000B
+#define EVENT_ADDRMAP 0x000C
+#define _EVENT_MAX 0x000C
/** Array mapping from message type codes to human-readable message
* type names. */
@@ -161,6 +162,7 @@ static int handle_control_closestream(connection_t *conn, uint32_t len,
const char *body);
static int handle_control_closecircuit(connection_t *conn, uint32_t len,
const char *body);
+static int write_stream_target_to_buf(connection_t *conn, char *buf, size_t len);
/** Given a possibly invalid message type code <b>cmd</b>, return a
* human-readable string equivalent. */
@@ -250,6 +252,7 @@ adjust_event_log_severity(void)
control_event_logmsg);
}
+/* DOCDOC */
static INLINE void
connection_write_str_to_buf(const char *s, connection_t *conn)
{
@@ -257,6 +260,7 @@ connection_write_str_to_buf(const char *s, connection_t *conn)
connection_write_to_buf(s, len, conn);
}
+/* DOCDOC ; test */
static size_t
write_escaped_data(const char *data, size_t len, int translate_newlines,
char **out)
@@ -288,50 +292,17 @@ write_escaped_data(const char *data, size_t len, int translate_newlines,
}
*outp++ = *data++;
}
- *outp++ = '\r';
- *outp++ = '\n';
+ if (outp < *out+2 || memcmp(outp-2, "\r\n", 2)) {
+ *outp++ = '\r';
+ *outp++ = '\n';
+ }
*outp++ = '.';
*outp++ = '\r';
*outp++ = '\n';
return outp - *out;
}
-#if 0
-static void
-connection_write_escaped_data_to_buf(const char *data, size_t len,
- int translate_newlines,
- connection_t *conn)
-{
- const char *next;
-
- while (len) {
- if (*data == '.')
- connection_write_to_buf(".", 1, conn);
-
- if (translate_newlines)
- next = tor_memmem(data, len, "\r\n", 2);
- else
- next = tor_memmem(data, len, "\r\n.", 3);
-
- if (next) {
- if (translate_newlines) {
- connection_write_to_buf(data, next-data, conn);
- connection_write_to_buf("\n", 1, conn);
- len -= (next-data+2);
- } else {
- connection_write_to_buf(data, next-data+2, conn);
- len -= (next-data+2);
- }
- data = next + 2;
- } else {
- connection_write_to_buf(data, len, conn);
- break;
- }
- }
- connection_write_to_buf(".\r\n", 3, conn);
-}
-#endif
-
+/* DOCDOC ; test */
static size_t
read_escaped_data(const char *data, size_t len, int translate_newlines,
char **out)
@@ -368,14 +339,54 @@ read_escaped_data(const char *data, size_t len, int translate_newlines,
return outp - *out;
}
+/** DOCDOC; test **/
static const char *
-get_escaped_string(const char *start, char **out, size_t *out_len)
+get_escaped_string(const char *start, size_t in_len_max,
+ char **out, size_t *out_len)
{
- /* XXXX V1 */
- return NULL;
-}
+ const char *cp, *end;
+ char *outp;
+ size_t len=0;
+
+ if (*start != '\"')
+ return NULL;
+
+ cp = start+1;
+ end = start+in_len_max;
+ /* Calculate length. */
+ while (1) {
+ if (cp >= end)
+ return NULL;
+ else if (*cp == '\\') {
+ if (++cp == end)
+ return NULL; /* Can't escape EOS. */
+ ++cp;
+ ++len;
+ } else if (*cp == '\"') {
+ break;
+ } else {
+ ++cp;
+ ++len;
+ }
+ }
+ end = cp;
+ outp = *out = tor_malloc(len+1);
+ *out_len = len;
+ cp = start+1;
+ while (cp < end) {
+ if (*cp == '\\')
+ ++cp;
+ *outp++ = *cp++;
+ }
+ *outp = '\0';
+ tor_assert((outp - *out) == *out_len);
+
+ return end+1;
+}
+
+/* DOCDOC */
static void
connection_printf_to_buf(connection_t *conn, const char *format, ...)
{
@@ -395,29 +406,6 @@ connection_printf_to_buf(connection_t *conn, const char *format, ...)
connection_write_to_buf(buf, len, conn);
}
-#if 0
-static void
-connection_write_reply_lines_to_buf(connection_t *conn,
- const char *code, smartlist_t *lines)
-{
- int i, len;
-
- tor_assert(strlen(code) == 3);
- len = smartlist_len(lines);
- if (!len)
- return;
-
- for (i=0; i < len-1; ++i) {
- connection_write_to_buf(code, 3, conn);
- connection_write_to_buf("-", 1, conn);
- connection_write_str_to_buf(smartlist_get(lines, i), conn);
- }
- connection_write_to_buf(code, 3, conn);
- connection_write_to_buf(" ", 1, conn);
- connection_write_str_to_buf(smartlist_get(lines, len-1), conn);
-}
-#endif
-
/** 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
@@ -514,15 +502,15 @@ send_control0_event(uint16_t event, uint32_t len, const char *body)
conns[i]->state == CONTROL_CONN_STATE_OPEN_V0 &&
conns[i]->event_mask & (1<<event)) {
send_control0_message(conns[i], CONTROL0_CMD_EVENT, buflen, buf);
- if (event == EVENT_ERR_MSG) {
+ if (event == EVENT_ERR_MSG)
_connection_controller_force_write(conns[i]);
- }
}
}
tor_free(buf);
}
+/* DOCDOC */
static void
send_control1_event(uint16_t event, const char *format, ...)
{
@@ -551,9 +539,8 @@ send_control1_event(uint16_t event, const char *format, ...)
conns[i]->state == CONTROL_CONN_STATE_OPEN_V1 &&
conns[i]->event_mask & (1<<event)) {
connection_write_to_buf(buf, len, conns[i]);
- if (event == EVENT_ERR_MSG) {
+ if (event == EVENT_ERR_MSG)
_connection_controller_force_write(conns[i]);
- }
}
}
}
@@ -591,6 +578,7 @@ handle_control_setconf(connection_t *conn, uint32_t len, char *body)
{
int r;
struct config_line_t *lines=NULL;
+ char *start = body;
int v0 = STATE_IS_V0(conn->state);
if (!v0) {
@@ -602,6 +590,7 @@ handle_control_setconf(connection_t *conn, uint32_t len, char *body)
++eq;
memcpy(outp, body, eq-body);
outp += (eq-body);
+ *outp++ = ' ';
body = eq+1;
if (*eq == '=') {
if (*body != '\"') {
@@ -610,7 +599,8 @@ handle_control_setconf(connection_t *conn, uint32_t len, char *body)
} else {
char *val;
size_t val_len;
- body = (char*)get_escaped_string(body, &val, &val_len);
+ body = (char*)get_escaped_string(body, (len - (body-start)),
+ &val, &val_len);
if (!body) {
connection_write_str_to_buf("551 Couldn't parse string\r\n", conn);
tor_free(config);
@@ -618,6 +608,7 @@ handle_control_setconf(connection_t *conn, uint32_t len, char *body)
}
memcpy(outp, val, val_len);
outp += val_len;
+ tor_free(val);
}
}
while (TOR_ISSPACE(*body))
@@ -702,6 +693,7 @@ handle_control_getconf(connection_t *conn, uint32_t body_len, const char *body)
}
} else {
struct config_line_t *answer = config_get_assigned_option(options,q);
+ /* XXXX handle non-set options in V1 at least*/
while (answer) {
struct config_line_t *next;
@@ -808,6 +800,8 @@ handle_control_setevents(connection_t *conn, uint32_t len, const char *body)
event_code = EVENT_ERR_MSG;
else if (!strcasecmp(ev, "NEWDESC"))
event_code = EVENT_NEW_DESC;
+ else if (!strcasecmp(ev, "ADDRMAP"))
+ event_code = EVENT_ADDRMAP;
else {
connection_printf_to_buf(conn, "552 Unrecognized event \"%s\"\r\n",
ev);
@@ -881,7 +875,7 @@ handle_control_authenticate(connection_t *conn, uint32_t len, const char *body)
password = tor_strdup("");
password_len = 0;
} else {
- if (!get_escaped_string(body, &password, &password_len)) {
+ if (!get_escaped_string(body, len, &password, &password_len)) {
connection_write_str_to_buf("551 Invalid quoted string\r\n", conn);
return 0;
}
@@ -1003,21 +997,29 @@ handle_control_signal(connection_t *conn, uint32_t len,
static int
handle_control_mapaddress(connection_t *conn, uint32_t len, const char *body)
{
- /* XXXX V1 */
smartlist_t *elts;
smartlist_t *lines;
smartlist_t *reply;
char *r;
size_t sz;
+ int v0 = STATE_IS_V0(conn->state);
lines = smartlist_create();
elts = smartlist_create();
reply = smartlist_create();
- smartlist_split_string(lines, body, "\n",
- SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
+ if (v0)
+ smartlist_split_string(lines, body, "\n",
+ SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
+ else
+ smartlist_split_string(lines, body, " ",
+ SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
+ /* XXXX Make errors conformant. */
SMARTLIST_FOREACH(lines, char *, line,
{
tor_strlower(line);
- smartlist_split_string(elts, line, " ", 0, 2);
+ if (v0)
+ smartlist_split_string(elts, line, " ", 0, 2);
+ else
+ smartlist_split_string(elts, line, "=", 0, 2);
if (smartlist_len(elts) == 2) {
const char *from = smartlist_get(elts,0);
const char *to = smartlist_get(elts,1);
@@ -1027,21 +1029,31 @@ handle_control_mapaddress(connection_t *conn, uint32_t len, const char *body)
log_fn(LOG_WARN,"Skipping invalid argument '%s' in MapAddress msg",to);
} else if (!strcmp(from, ".") || !strcmp(from, "0.0.0.0")) {
const char *addr = addressmap_register_virtual_address(
- strcmp(from,".") ? RESOLVED_TYPE_HOSTNAME : RESOLVED_TYPE_IPV4,
+ !strcmp(from,".") ? RESOLVED_TYPE_HOSTNAME : RESOLVED_TYPE_IPV4,
tor_strdup(to));
if (!addr) {
log_fn(LOG_WARN,
"Unable to allocate address for '%s' in MapAddress msg",
safe_str(line));
} else {
- size_t anslen = strlen(addr)+strlen(to)+2;
+ size_t anslen = strlen(addr)+strlen(to)+8;
char *ans = tor_malloc(anslen);
- tor_snprintf(ans, anslen, "%s %s", addr, to);
+ if (v0)
+ tor_snprintf(ans, anslen, "%s %s", addr, to);
+ else
+ tor_snprintf(ans, anslen, "250-%s=%s", addr, to);
smartlist_add(reply, ans);
}
} else {
addressmap_register(from, tor_strdup(to), 1);
- smartlist_add(reply, tor_strdup(line));
+ if (v0)
+ smartlist_add(reply, tor_strdup(line));
+ else {
+ size_t anslen = strlen(line)+8;
+ char *ans = tor_malloc(anslen);
+ tor_snprintf(ans, anslen, "250-%s", line);
+ smartlist_add(reply, ans);
+ }
}
} else {
log_fn(LOG_WARN, "Skipping MapAddress line with wrong number of items.");
@@ -1053,8 +1065,15 @@ handle_control_mapaddress(connection_t *conn, uint32_t len, const char *body)
smartlist_free(lines);
smartlist_free(elts);
- r = smartlist_join_strings(reply, "\n", 1, &sz);
- send_control_done2(conn,r,sz);
+ if (v0) {
+ r = smartlist_join_strings(reply, "\n", 1, &sz);
+ send_control_done2(conn,r,sz);
+ } else {
+ if (smartlist_len(reply))
+ ((char*)smartlist_get(reply,smartlist_len(reply)-1))[3] = ' ';
+ r = smartlist_join_strings(reply, "\r\n", 1, &sz);
+ connection_write_to_buf(r, sz, conn);
+ }
SMARTLIST_FOREACH(reply, char *, cp, tor_free(cp));
smartlist_free(reply);
@@ -1086,6 +1105,106 @@ handle_getinfo_helper(const char *question, char **answer)
list_server_status(routerlist->routers, answer) < 0) {
return -1;
}
+ } else if (!strcmp(question, "circuit-status")) {
+ circuit_t *circ;
+ smartlist_t *status = smartlist_create();
+ for (circ = _circuit_get_global_list(); circ; circ = circ->next) {
+ char *s, *path;
+ size_t slen;
+ const char *state;
+ if (! CIRCUIT_IS_ORIGIN(circ) || circ->marked_for_close)
+ continue;
+ path = circuit_list_path(circ,0);
+ if (circ->state == CIRCUIT_STATE_OPEN)
+ state = "BUILT";
+ else if (strlen(path))
+ state = "EXTENDED";
+ else
+ state = "LAUNCHED";
+
+ slen = strlen(path)+strlen(state)+20;
+ s = tor_malloc(slen+1);
+ tor_snprintf(s, slen, "%lu %s %s", (unsigned long)circ->global_identifier,
+ state, path);
+ smartlist_add(status, s);
+ tor_free(path);
+ }
+ *answer = smartlist_join_strings(status, "\r\n", 1, NULL);
+ SMARTLIST_FOREACH(status, char *, cp, tor_free(cp));
+ smartlist_free(status);
+ } else if (!strcmp(question, "stream-status")) {
+ connection_t **conns;
+ int n_conns, i;
+ char buf[256];
+ smartlist_t *status = smartlist_create();
+ get_connection_array(&conns, &n_conns);
+ for (i=0; i < n_conns; ++i) {
+ const char *state;
+ char *s;
+ size_t slen;
+ circuit_t *circ;
+ if (conns[i]->type != CONN_TYPE_AP ||
+ conns[i]->marked_for_close ||
+ conns[i]->state == AP_CONN_STATE_SOCKS_WAIT)
+ continue;
+ switch (conns[i]->state)
+ {
+ case AP_CONN_STATE_CONTROLLER_WAIT:
+ case AP_CONN_STATE_CIRCUIT_WAIT:
+ if (conns[i]->socks_request &&
+ conns[i]->socks_request->command == SOCKS_COMMAND_RESOLVE)
+ state = "NEWRESOLVE";
+ else
+ state = "NEW";
+ break;
+ case AP_CONN_STATE_RENDDESC_WAIT:
+ case AP_CONN_STATE_CONNECT_WAIT:
+ state = "SENTCONNECT"; break;
+ case AP_CONN_STATE_RESOLVE_WAIT:
+ state = "SENTRESOLVE"; break;
+ case AP_CONN_STATE_OPEN:
+ state = "SUCCEEDED"; break;
+ default:
+ log_fn(LOG_WARN, "Asked for stream in unknown state %d",
+ conns[i]->state);
+ continue;
+ }
+ circ = circuit_get_by_edge_conn(conns[i]);
+ write_stream_target_to_buf(conns[i], buf, sizeof(buf));
+ slen = strlen(buf)+strlen(state)+32;
+ s = tor_malloc(slen+1);
+ tor_snprintf(s, slen, "%lu %s %lu %s",
+ (unsigned long) conns[i]->global_identifier,state,
+ circ?(unsigned long)circ->global_identifier : 0ul,
+ buf);
+ smartlist_add(status, s);
+ }
+ *answer = smartlist_join_strings(status, "\r\n", 1, NULL);
+ SMARTLIST_FOREACH(status, char *, cp, tor_free(cp));
+ smartlist_free(status);
+ } else if (!strcmp(question, "orconn-status")) {
+ connection_t **conns;
+ int n_conns, i;
+ smartlist_t *status = smartlist_create();
+ get_connection_array(&conns, &n_conns);
+ for (i=0; i < n_conns; ++i) {
+ const char *state;
+ char *s;
+ size_t slen;
+ if (conns[i]->type != CONN_TYPE_OR || conns[i]->marked_for_close)
+ continue;
+ if (conns[i]->state == OR_CONN_STATE_OPEN)
+ state = "CONNECTED";
+ else
+ state = "LAUNCHED";
+ slen = strlen(conns[i]->nickname)+strlen(state)+2;
+ s = tor_malloc(slen+1);
+ tor_snprintf(s, slen, "%s %s",conns[i]->nickname,state);
+ smartlist_add(status, s);
+ }
+ *answer = smartlist_join_strings(status, "\r\n", 1, NULL);
+ SMARTLIST_FOREACH(status, char *, cp, tor_free(cp));
+ smartlist_free(status);
} else if (!strcmpstart(question, "addr-mappings/")) {
time_t min_e, max_e;
smartlist_t *mappings;
@@ -1152,13 +1271,13 @@ handle_control_getinfo(connection_t *conn, uint32_t len, const char *body)
if (smartlist_len(unrecognized)) {
int i;
tor_assert(!v0);
- for (i=0; i < len-1; ++i)
+ for (i=0; i < smartlist_len(unrecognized)-1; ++i)
connection_printf_to_buf(conn,
- "552-Unrecognized configuration key \"%s\"\r\n",
+ "552-Unrecognized key \"%s\"\r\n",
(char*)smartlist_get(unrecognized, i));
connection_printf_to_buf(conn,
- "552 Unrecognized configuration key \"%s\"\r\n",
- (char*)smartlist_get(unrecognized, len-1));
+ "552 Unrecognized key \"%s\"\r\n",
+ (char*)smartlist_get(unrecognized, i));
goto done;
}
@@ -1174,12 +1293,14 @@ handle_control_getinfo(connection_t *conn, uint32_t len, const char *body)
char *v = smartlist_get(answers, i+1);
/*XXXX Not an adequate test! XXXX011 */
if (!strchr(v, '\n') && !strchr(v, '\r')) {
- connection_printf_to_buf(conn, "250-%s=%s\r\n", k, v);
+ connection_printf_to_buf(conn, "250-%s=", k);
+ connection_write_str_to_buf(v, conn);
+ connection_write_str_to_buf("\r\n", conn);
} else {
char *esc = NULL;
size_t len;
len = write_escaped_data(v, strlen(v), 1, &esc);
- connection_printf_to_buf(conn, "250+%s=", k);
+ connection_printf_to_buf(conn, "250+%s=\r\n", k);
connection_write_to_buf(esc, len, conn);
tor_free(esc);
}
@@ -1371,7 +1492,6 @@ handle_control_attachstream(connection_t *conn, uint32_t len,
return 0;
}
-
if (ap_conn->state != AP_CONN_STATE_CONTROLLER_WAIT) {
if (STATE_IS_V0(conn->state)) {
send_control0_error(conn, ERR_NO_STREAM,
@@ -1679,6 +1799,7 @@ connection_control_reached_eof(connection_t *conn)
return 0;
}
+/* DOCDOC */
static int
connection_control_process_inbuf_v1(connection_t *conn)
{
@@ -1812,6 +1933,7 @@ connection_control_process_inbuf_v1(connection_t *conn)
goto again;
}
+/* DOCDOC */
static int
connection_control_process_inbuf_v0(connection_t *conn)
{
@@ -2015,6 +2137,22 @@ control_event_circuit_status(circuit_t *circ, circuit_status_event_t tp)
return 0;
}
+/** DOCDOC */
+static int
+write_stream_target_to_buf(connection_t *conn, char *buf, size_t len)
+{
+ char buf2[256];
+ if (conn->chosen_exit_name)
+ if (tor_snprintf(buf2, sizeof(buf2), ".%s.exit", conn->chosen_exit_name)<0)
+ return -1;
+ if (tor_snprintf(buf, len, "%s%s:%d",
+ conn->socks_request->address,
+ conn->chosen_exit_name ? buf2 : "",
+ conn->socks_request->port)<0)
+ return -1;
+ return 0;
+}
+
/** Something has happened to the stream associated with AP connection
* <b>conn</b>: tell any interested control connections. */
int
@@ -2022,19 +2160,14 @@ control_event_stream_status(connection_t *conn, stream_status_event_t tp)
{
char *msg;
size_t len;
- char buf[256], buf2[256];
+ char buf[256];
tor_assert(conn->type == CONN_TYPE_AP);
tor_assert(conn->socks_request);
if (!EVENT_IS_INTERESTING(EVENT_STREAM_STATUS))
return 0;
- if (conn->chosen_exit_name)
- tor_snprintf(buf2, sizeof(buf2), ".%s.exit", conn->chosen_exit_name);
- tor_snprintf(buf, sizeof(buf), "%s%s:%d",
- conn->socks_request->address,
- conn->chosen_exit_name ? buf2 : "",
- conn->socks_request->port);
+ write_stream_target_to_buf(conn, buf, sizeof(buf));
if (EVENT_IS_INTERESTING0(EVENT_STREAM_STATUS)) {
len = strlen(buf);
msg = tor_malloc(5+len+1);
@@ -2047,6 +2180,7 @@ control_event_stream_status(connection_t *conn, stream_status_event_t tp)
}
if (EVENT_IS_INTERESTING0(EVENT_STREAM_STATUS)) {
const char *status;
+ circuit_t *circ;
switch (tp)
{
case STREAM_EVENT_SENT_CONNECT: status = "SENTCONNECT"; break;
@@ -2061,10 +2195,12 @@ control_event_stream_status(connection_t *conn, stream_status_event_t tp)
log_fn(LOG_WARN, "Unrecognized status code %d", (int)tp);
return 0;
}
+ circ = circuit_get_by_edge_conn(conn);
send_control1_event(EVENT_STREAM_STATUS,
- "650 STREAM %lu %s %s\r\n",
- (unsigned long)conn->global_identifier,
- status, buf);
+ "650 STREAM %lu %s %lu %s\r\n",
+ (unsigned long)conn->global_identifier, status,
+ circ?(unsigned long)circ->global_identifier : 0ul,
+ buf);
}
return 0;
}
@@ -2167,7 +2303,7 @@ control_event_logmsg(int severity, const char *msg)
if (*cp == '\r' || *cp == '\n')
*cp = ' ';
}
- switch(severity) {
+ switch (severity) {
case LOG_INFO: s = "INFO"; break;
case LOG_NOTICE: s = "NOTICE"; break;
case LOG_WARN: s = "WARN"; break;
@@ -2215,6 +2351,25 @@ control_event_descriptors_changed(smartlist_t *routers)
return 0;
}
+/** DOCDOC */
+int
+control_event_address_mapped(const char *from, const char *to, time_t expires)
+{
+ if (!EVENT_IS_INTERESTING1(EVENT_ADDRMAP))
+ return 0;
+
+ if (expires < 3)
+ send_control1_event(EVENT_ADDRMAP, "650 ADDRMAP %s %s NEVER\r\n", from, to);
+ else {
+ char buf[ISO_TIME_LEN+1];
+ format_local_iso_time(buf,expires);
+ send_control1_event(EVENT_ADDRMAP, "650 ADDRMAP %s %s \"%s\"\r\n",
+ from, to, buf);
+ }
+
+ return 0;
+}
+
/** Choose a random authentication cookie and write it to disk.
* Anybody who can read the cookie from disk will be considered
* authorized to use the control connection. */