diff options
-rw-r--r-- | src/or/circuitbuild.c | 38 | ||||
-rw-r--r-- | src/or/circuitlist.c | 9 | ||||
-rw-r--r-- | src/or/circuituse.c | 2 | ||||
-rw-r--r-- | src/or/connection.c | 7 | ||||
-rw-r--r-- | src/or/connection_edge.c | 5 | ||||
-rw-r--r-- | src/or/connection_or.c | 9 | ||||
-rw-r--r-- | src/or/control.c | 103 | ||||
-rw-r--r-- | src/or/dirserv.c | 6 | ||||
-rw-r--r-- | src/or/main.c | 1 | ||||
-rw-r--r-- | src/or/or.h | 40 | ||||
-rw-r--r-- | src/or/router.c | 5 | ||||
-rw-r--r-- | src/or/routerlist.c | 2 | ||||
-rw-r--r-- | src/or/test.c | 10 |
13 files changed, 199 insertions, 38 deletions
diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index f163abe2b..170cde8c2 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -63,6 +63,40 @@ static uint16_t get_unique_circ_id_by_conn(connection_t *conn, int circ_id_type) return test_circ_id; } +/** Allocate and return a comma-separated list of the currently built + * elements of circuit_t. + */ +char *circuit_list_path(circuit_t *circ) +{ + struct crypt_path_t *hop; + routerinfo_t *r; + smartlist_t *elements; + char *s; + tor_assert(CIRCUIT_IS_ORIGIN(circ)); + tor_assert(circ->cpath); + + elements = smartlist_create(); + + for (hop = circ->cpath; hop; hop = hop->next) { + if (hop->state != CPATH_STATE_OPEN) + break; + if ((r = router_get_by_digest(hop->identity_digest))) { + smartlist_add(elements, tor_strdup(r->nickname)); + } else if (circ->purpose == CIRCUIT_PURPOSE_C_REND_JOINED) { + smartlist_add(elements, tor_strdup("<rendezvous splice>")); + } else { + s = tor_malloc(HEX_DIGEST_LEN+2); + s[0]='$'; + base16_encode(s+1,HEX_DIGEST_LEN+1,hop->identity_digest,DIGEST_LEN); + smartlist_add(elements, s); + } + } + + s = smartlist_join_strings(elements, ",", 0, NULL); + SMARTLIST_FOREACH(elements, char*, cp, tor_free(cp)); + return s; +} + /** Log, at severity <b>severity</b>, the nicknames of each router in * circ's cpath. Also log the length of the cpath, and the intended * exit point. @@ -220,6 +254,8 @@ circuit_t *circuit_establish_circuit(uint8_t purpose, return NULL; } + control_event_circuit_status(circ, CIRC_EVENT_LAUNCHED); + /* now see if we're already connected to the first OR in 'route' */ tor_assert(firsthop); @@ -604,6 +640,8 @@ int circuit_finish_handshake(circuit_t *circ, char *reply) { hop->state = CPATH_STATE_OPEN; log_fn(LOG_INFO,"finished"); circuit_log_path(LOG_INFO,circ); + control_event_circuit_status(circ, CIRC_EVENT_EXTENDED); + return 0; } diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c index dc90b9bc9..ad31d6f8e 100644 --- a/src/or/circuitlist.c +++ b/src/or/circuitlist.c @@ -74,6 +74,7 @@ void circuit_close_all_marked(void) */ circuit_t *circuit_new(uint16_t p_circ_id, connection_t *p_conn) { circuit_t *circ; + static uint32_t n_circuits_allocated = 0; circ = tor_malloc_zero(sizeof(circuit_t)); circ->magic = CIRCUIT_MAGIC; @@ -93,6 +94,7 @@ circuit_t *circuit_new(uint16_t p_circ_id, connection_t *p_conn) { circ->deliver_window = CIRCWINDOW_START; circ->next_stream_id = crypto_pseudo_rand_int(1<<16); + circ->global_identifier = n_circuits_allocated++; circuit_add(circ); @@ -353,10 +355,15 @@ int _circuit_mark_for_close(circuit_t *circ) { * links worked and which didn't. */ if (circ->state != CIRCUIT_STATE_OPEN) { - if(CIRCUIT_IS_ORIGIN(circ)) + if(CIRCUIT_IS_ORIGIN(circ)) { circuit_build_failed(circ); /* take actions if necessary */ + } circuit_rep_hist_note_result(circ); } + if (CIRCUIT_IS_ORIGIN(circ)) { + control_event_circuit_status(circ, + (circ->state == CIRCUIT_STATE_OPEN)?CIRC_EVENT_CLOSED:CIRC_EVENT_FAILED); + } if (circ->purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) { tor_assert(circ->state == CIRCUIT_STATE_OPEN); /* treat this like getting a nack from it */ diff --git a/src/or/circuituse.c b/src/or/circuituse.c index 6ec7a640b..ba4f65047 100644 --- a/src/or/circuituse.c +++ b/src/or/circuituse.c @@ -489,6 +489,8 @@ circuit_expire_old_circuits(void) */ void circuit_has_opened(circuit_t *circ) { + control_event_circuit_status(circ, CIRC_EVENT_BUILT); + switch(circ->purpose) { case CIRCUIT_PURPOSE_C_ESTABLISH_REND: rend_client_rendcirc_has_opened(circ); diff --git a/src/or/connection.c b/src/or/connection.c index 79c5b997f..7d3b4c43b 100644 --- a/src/or/connection.c +++ b/src/or/connection.c @@ -198,12 +198,15 @@ void connection_about_to_close_connection(connection_t *conn) case CONN_TYPE_OR: /* Remember why we're closing this connection. */ if (conn->state != OR_CONN_STATE_OPEN) { - if(connection_or_nonopen_was_started_here(conn)) + if(connection_or_nonopen_was_started_here(conn)) { rep_hist_note_connect_failed(conn->identity_digest, time(NULL)); + control_event_or_conn_status(conn, OR_CONN_EVENT_FAILED); + } } else if (0) { // XXX reason == CLOSE_REASON_UNUSED_OR_CONN) { rep_hist_note_disconnect(conn->identity_digest, time(NULL)); } else if(conn->identity_digest) { rep_hist_note_connection_died(conn->identity_digest, time(NULL)); + control_event_or_conn_status(conn, OR_CONN_EVENT_CLOSED); } break; case CONN_TYPE_AP: @@ -212,6 +215,8 @@ void connection_about_to_close_connection(connection_t *conn) connection_ap_handshake_socks_reply(conn, NULL, 0, 0); conn->socks_request->has_finished = 1; conn->hold_open_until_flushed = 1; + } else { + control_event_stream_status(conn, STREAM_EVENT_CLOSED); } break; case CONN_TYPE_EXIT: diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c index e7eec0533..51506b362 100644 --- a/src/or/connection_edge.c +++ b/src/or/connection_edge.c @@ -521,6 +521,7 @@ int connection_ap_handshake_send_begin(connection_t *ap_conn, circuit_t *circ) ap_conn->deliver_window = STREAMWINDOW_START; ap_conn->state = AP_CONN_STATE_CONNECT_WAIT; log_fn(LOG_INFO,"Address/port sent, ap socket %d, n_circ_id %d",ap_conn->s,circ->n_circ_id); + control_event_stream_status(ap_conn, STREAM_EVENT_SENT_CONNECT); return 0; } @@ -561,6 +562,7 @@ int connection_ap_handshake_send_resolve(connection_t *ap_conn, circuit_t *circ) ap_conn->state = AP_CONN_STATE_RESOLVE_WAIT; log_fn(LOG_INFO,"Address sent for resolve, ap socket %d, n_circ_id %d",ap_conn->s,circ->n_circ_id); + control_event_stream_status(ap_conn, STREAM_EVENT_SENT_RESOLVE); return 0; } @@ -689,6 +691,9 @@ void connection_ap_handshake_socks_reply(connection_t *conn, char *reply, size_t replylen, int success) { char buf[256]; + control_event_stream_status(conn, + success ? STREAM_EVENT_SUCCEEDED : STREAM_EVENT_FAILED); + if(replylen) { /* we already have a reply in mind */ connection_write_to_buf(reply, replylen, conn); return; diff --git a/src/or/connection_or.c b/src/or/connection_or.c index 02cb4fa23..2852ad599 100644 --- a/src/or/connection_or.c +++ b/src/or/connection_or.c @@ -140,8 +140,9 @@ connection_or_init_conn_from_address(connection_t *conn, if (n) { conn->nickname = tor_strdup(n); } else { - conn->nickname = tor_malloc(HEX_DIGEST_LEN+1); - base16_encode(conn->nickname, HEX_DIGEST_LEN+1, + conn->nickname = tor_malloc(HEX_DIGEST_LEN+2); + conn->nickname[0] = '$'; + base16_encode(conn->nickname+1, HEX_DIGEST_LEN+1, conn->identity_digest, DIGEST_LEN); } tor_free(conn->address); @@ -223,10 +224,12 @@ connection_t *connection_or_connect(uint32_t addr, uint16_t port, /* set up conn so it's got all the data we need to remember */ connection_or_init_conn_from_address(conn, addr, port, id_digest); conn->state = OR_CONN_STATE_CONNECTING; + control_event_or_conn_status(conn, OR_CONN_EVENT_LAUNCHED); switch(connection_connect(conn, conn->address, addr, port)) { case -1: router_mark_as_down(conn->identity_digest); + control_event_or_conn_status(conn, OR_CONN_EVENT_FAILED); connection_free(conn); return NULL; case 0: @@ -376,6 +379,7 @@ connection_tls_finish_handshake(connection_t *conn) { log_fn(options.DirPort ? LOG_WARN : LOG_INFO, "Other side (%s:%d) is '%s', but we tried to connect to '%s'", conn->address, conn->port, nickname, conn->nickname); + control_event_or_conn_status(conn, OR_CONN_EVENT_FAILED); return -1; } } else { @@ -393,6 +397,7 @@ connection_tls_finish_handshake(connection_t *conn) { circuit_n_conn_done(conn, 1); /* send the pending creates, if any. */ /* Note the success */ rep_hist_note_connect_succeeded(conn->identity_digest, time(NULL)); + control_event_or_conn_status(conn, OR_CONN_EVENT_CONNECTED); return 0; } diff --git a/src/or/control.c b/src/or/control.c index 877342560..5ffcd2807 100644 --- a/src/or/control.c +++ b/src/or/control.c @@ -43,6 +43,8 @@ static const char *CONTROL_COMMANDS[] = { "authenticate", }; +extern or_options_t options; + static uint32_t global_event_mask = 0; static void update_global_event_mask(void); @@ -131,17 +133,57 @@ send_control_event(uint16_t event, uint16_t len, const char *body) } } -static int +static int handle_control_setconf(connection_t *conn, uint16_t len, const char *body) { /* XXXX009 NM */ return 0; } -static int handle_control_getconf(connection_t *conn, uint16_t len, + +static int handle_control_getconf(connection_t *conn, uint16_t body_len, const char *body) { - /* XXXX009 NM */ + smartlist_t *answer_elements = NULL; + char *msg = NULL; + size_t msg_len; + + if (body[body_len-1] != '\0') { + send_control_error(conn, ERR_UNSPECIFIED, + "getconf message body not nul-terminated."); + return 0; + } + /* Now we can be sure that body will end in a nul-terminated string. */ + + answer_elements = smartlist_create(); + while (body_len) { + size_t question_len = strlen(body); + struct config_line_t *answer = config_get_assigned_option(&options,body); + if (!answer) { + send_control_error(conn, ERR_UNRECOGNIZED_CONFIG_KEY, body); + goto done; + } else { + while (answer) { + struct config_line_t *next; + smartlist_add(answer_elements, answer->key); + smartlist_add(answer_elements, answer->value); + next = answer->next; + tor_free(answer); + answer = next; + } + } + body += question_len+1; + body_len -= question_len+1; + } + + msg = smartlist_join_strings2(answer_elements, "\0", 1, 0, &msg_len); + send_control_message(conn, CONTROL_CMD_CONFVALUE, msg_len, msg); + + done: + SMARTLIST_FOREACH(answer_elements, char *, cp, tor_free(cp)); + smartlist_free(answer_elements); + tor_free(msg); + return 0; } static int handle_control_setevents(connection_t *conn, uint16_t len, @@ -263,37 +305,63 @@ int connection_control_process_inbuf(connection_t *conn) { goto again; /* There might be more data. */ } -int control_event_circuit_status(circuit_t *circ) +int control_event_circuit_status(circuit_t *circ, circuit_status_event_t tp) { + char *path, *msg; + size_t path_len; if (!EVENT_IS_INTERESTING(EVENT_CIRCUIT_STATUS)) return 0; - - /* XXXXX009 NM */ - + tor_assert(circ); + tor_assert(CIRCUIT_IS_ORIGIN(circ)); + + path = circuit_list_path(circ); + path_len = strlen(path); + msg = tor_malloc(1+4+path_len+1); /* event, circid, path, NUL. */ + msg[0] = (uint8_t) tp; + set_uint32(msg+1, htonl(circ->global_identifier)); + strlcpy(msg+5,path,path_len+1); + + send_control_event(EVENT_STREAM_STATUS, (uint16_t)(path_len+6), msg); + tor_free(path); + tor_free(msg); return 0; } -int control_event_stream_status(connection_t *conn) +int control_event_stream_status(connection_t *conn, stream_status_event_t tp) { + char *msg; + size_t len; tor_assert(conn->type == CONN_TYPE_AP); + tor_assert(conn->socks_request); if (!EVENT_IS_INTERESTING(EVENT_STREAM_STATUS)) return 0; - /* XXXXX009 NM */ + len = strlen(conn->socks_request->address); + msg = tor_malloc(5+len+1); + msg[0] = (uint8_t) tp; + set_uint32(msg+1, htonl(conn->s)); /* ???? Is this a security problem? */ + strlcpy(msg+5, conn->socks_request->address, len+1); + send_control_event(EVENT_STREAM_STATUS, (uint16_t)(5+len+1), msg); + tor_free(msg); return 0; } -int control_event_or_conn_status(connection_t *conn) +int control_event_or_conn_status(connection_t *conn,or_conn_status_event_t tp) { + char buf[HEX_DIGEST_LEN+3]; /* status, dollar, identity, NUL */ + size_t len; + tor_assert(conn->type == CONN_TYPE_OR); if (!EVENT_IS_INTERESTING(EVENT_OR_CONN_STATUS)) return 0; - /* XXXXX009 NM */ - + 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); return 0; } @@ -311,19 +379,18 @@ int control_event_bandwidth_used(uint32_t n_read, uint32_t n_written) return 0; } -int control_event_warning(const char *msg) +void control_event_logmsg(int severity, const char *msg) { size_t len; + if (severity > LOG_WARN) /* Less important than warning? ignore for now. */ + return; if (!EVENT_IS_INTERESTING(EVENT_WARNING)) - return 0; + return; len = strlen(msg); - send_control_event(EVENT_WARNING, len+1, msg); - - return 0; + send_control_event(EVENT_WARNING, (uint16_t)(len+1), msg); } - /* Local Variabls: mode:c diff --git a/src/or/dirserv.c b/src/or/dirserv.c index 2483efc74..56c1446f1 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -523,9 +523,9 @@ list_server_status(char **running_routers_out, char **router_status_out) }); if (running_routers_out) - *running_routers_out = smartlist_join_strings(rr_entries, " ", 0); + *running_routers_out = smartlist_join_strings(rr_entries, " ", 0,NULL); if (router_status_out) - *router_status_out = smartlist_join_strings(rs_entries, " ", 0); + *router_status_out = smartlist_join_strings(rs_entries, " ", 0,NULL); SMARTLIST_FOREACH(rr_entries, char *, cp, tor_free(cp)); SMARTLIST_FOREACH(rs_entries, char *, cp, tor_free(cp)); @@ -611,7 +611,7 @@ dirserv_dump_directory_to_string(char *s, size_t maxlen, smartlist_split_string(versions, ln->value, ",", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); } - recommended_versions = smartlist_join_strings(versions,",",0); + recommended_versions = smartlist_join_strings(versions,",",0,NULL); SMARTLIST_FOREACH(versions,char *,s,tor_free(s)); smartlist_free(versions); } diff --git a/src/or/main.c b/src/or/main.c index bd5bc883b..812f8c96a 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -971,6 +971,7 @@ static int init_from_config(int argc, char **argv) { /* Close the temporary log we used while starting up, if it isn't already * gone. */ close_temp_logs(); + add_callback_log(LOG_WARN, LOG_ERR, control_event_logmsg); /* Start backgrounding the process, if requested. */ if (options.RunAsDaemon) { diff --git a/src/or/or.h b/src/or/or.h index 76ec2e1d5..a25a909c8 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -822,6 +822,10 @@ struct circuit_t { * is not marked for close. */ struct circuit_t *rend_splice; + /** Quasi-global identifier for this circuit; used for control.c */ + /* XXXX009 NM This can get re-used after 2**32 circuits. */ + uint32_t global_identifier; + struct circuit_t *next; /**< Next circuit in linked list. */ }; @@ -1000,6 +1004,7 @@ void assert_buf_ok(buf_t *buf); /********************************* circuitbuild.c **********************/ +char *circuit_list_path(circuit_t *circ); void circuit_log_path(int severity, circuit_t *circ); void circuit_rep_hist_note_result(circuit_t *circ); void circuit_dump_by_conn(connection_t *conn, int severity); @@ -1084,6 +1089,8 @@ void config_parse_exit_policy(struct config_line_t *cfg, struct exit_policy_t **dest); void exit_policy_free(struct exit_policy_t *p); const char *get_data_directory(or_options_t *options); +struct config_line_t *config_get_assigned_option(or_options_t *options, + const char *key); /********************************* connection.c ***************************/ @@ -1202,14 +1209,37 @@ void connection_or_update_nickname(connection_t *conn); /********************************* control.c ***************************/ +typedef enum circuit_status_event_t { + CIRC_EVENT_LAUNCHED = 0, + CIRC_EVENT_BUILT = 1, + CIRC_EVENT_EXTENDED = 2, + CIRC_EVENT_FAILED = 3, + CIRC_EVENT_CLOSED = 4, +} circuit_status_event_t; + +typedef enum stream_status_event_t { + STREAM_EVENT_SENT_CONNECT = 0, + STREAM_EVENT_SENT_RESOLVE = 1, + STREAM_EVENT_SUCCEEDED = 2, + STREAM_EVENT_FAILED = 3, + STREAM_EVENT_CLOSED = 4 +} stream_status_event_t; + +typedef enum or_conn_status_event_t { + OR_CONN_EVENT_LAUNCHED = 0, + OR_CONN_EVENT_CONNECTED = 1, + OR_CONN_EVENT_FAILED = 2, + OR_CONN_EVENT_CLOSED = 3, +} or_conn_status_event_t; + int connection_control_finished_flushing(connection_t *conn); int connection_control_process_inbuf(connection_t *conn); -int control_event_circuit_status(circuit_t *circ); -int control_event_stream_status(connection_t *conn); -int control_event_or_conn_status(connection_t *conn); +int control_event_circuit_status(circuit_t *circ, circuit_status_event_t e); +int control_event_stream_status(connection_t *conn, stream_status_event_t e); +int control_event_or_conn_status(connection_t *conn, or_conn_status_event_t e); int control_event_bandwidth_used(uint32_t n_read, uint32_t n_written); -int control_event_warning(const char *msg); +void control_event_logmsg(int severity, const char *msg); /********************************* cpuworker.c *****************************/ @@ -1543,7 +1573,7 @@ int router_get_runningrouters_hash(const char *s, char *digest); int router_parse_list_from_string(const char **s, routerlist_t **dest, smartlist_t *good_nickname_list, - int rr_format, + int rr_format, time_t published); int router_parse_routerlist_from_directory(const char *s, routerlist_t **dest, diff --git a/src/or/router.c b/src/or/router.c index 8b1ba1763..989e7aed9 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -640,8 +640,9 @@ int router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router, bandwidth_usage = rep_hist_get_bandwidth_lines(); if (router->declared_family && smartlist_len(router->declared_family)) { - char *s = smartlist_join_strings(router->declared_family, " ", 0); - size_t n = strlen(s) + strlen("opt family ") + 2; /* 1 for \n, 1 for \0. */ + size_t n; + char *s = smartlist_join_strings(router->declared_family, " ", 0, &n); + n += strlen("opt family ") + 2; /* 1 for \n, 1 for \0. */ family_line = tor_malloc(n); tor_snprintf(family_line, n, "opt family %s\n", s); tor_free(s); diff --git a/src/or/routerlist.c b/src/or/routerlist.c index 0460de283..2ed8d1b6a 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -1167,7 +1167,7 @@ int routers_update_status_from_entry(smartlist_t *routers, r->status_set_at = time(NULL); } }); - + return 0; } diff --git a/src/or/test.c b/src/or/test.c index d278d771d..2cece29d7 100644 --- a/src/or/test.c +++ b/src/or/test.c @@ -566,19 +566,19 @@ test_util(void) { test_streq("a", smartlist_get(sl, 1)); test_streq("bc", smartlist_get(sl, 2)); test_streq("", smartlist_get(sl, 3)); - cp = smartlist_join_strings(sl, "", 0); + cp = smartlist_join_strings(sl, "", 0, NULL); test_streq(cp, "abcabc"); tor_free(cp); - cp = smartlist_join_strings(sl, "!", 0); + cp = smartlist_join_strings(sl, "!", 0, NULL); test_streq(cp, "abc!a!bc!"); tor_free(cp); - cp = smartlist_join_strings(sl, "XY", 0); + cp = smartlist_join_strings(sl, "XY", 0, NULL); test_streq(cp, "abcXYaXYbcXY"); tor_free(cp); - cp = smartlist_join_strings(sl, "XY", 1); + cp = smartlist_join_strings(sl, "XY", 1, NULL); test_streq(cp, "abcXYaXYbcXYXY"); tor_free(cp); - cp = smartlist_join_strings(sl, "", 1); + cp = smartlist_join_strings(sl, "", 1, NULL); test_streq(cp, "abcabc"); tor_free(cp); |