diff --git a/ChangeLog b/ChangeLog index 8ce2a10627..35cf67e35d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -62,6 +62,8 @@ Changes in version 0.1.2.5-xxxx - 200?-??-?? - Reimplement GETINFO so that info/names stays in sync with the actual keys. - Implement "GETINFO fingerprint". + - Implement "SETEVENTS GUARD" so controllers can get updates on + entry guard status as it changes. o Controller bugfixes: - Report the circuit number correctly in STREAM CLOSED events. (Bug diff --git a/doc/control-spec.txt b/doc/control-spec.txt index 08e91cfb9f..1987fd9494 100644 --- a/doc/control-spec.txt +++ b/doc/control-spec.txt @@ -1134,10 +1134,12 @@ I DIR_ALL_UNREACHABLE 4.1.11. Our set of guard nodes has changed Syntax: - "650" SP "GUARDS" SP Type SP ... + "650" SP "GUARDS" SP Type SP Name SP Status ... CRLF Type = "ENTRY" - ... - [needs to be fleshed out; not implemented yet] + Name = The (possibly verbose) nickname of the guard effected. + Status = "NEW" | "UP" | "DOWN" | "BAD" | "GOOD" | "DROPPED" + + [explain states. XXX] 4.1.12. Network status has changed diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index c76667a2bb..5de96f670e 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -1797,6 +1797,7 @@ entry_guard_set_status(entry_guard_t *e, routerinfo_t *ri, e->nickname, buf, reason); e->bad_since = now; + control_event_guard(e->nickname, e->identity, "BAD"); changed = 1; } else if (!reason && e->bad_since) { /* There's nothing wrong with the router any more. */ @@ -1805,6 +1806,7 @@ entry_guard_set_status(entry_guard_t *e, routerinfo_t *ri, "marking as ok.", e->nickname, buf); e->bad_since = 0; + control_event_guard(e->nickname, e->identity, "GOOD"); changed = 1; } @@ -1916,6 +1918,27 @@ log_entry_guards(int severity) tor_free(s); } +/** DOCDOC */ +static void +control_event_guard_deferred(void) +{ +#if 0 + int n = 0; + or_options_t *options = get_options(); + if (!entry_guards) + return; + SMARTLIST_FOREACH(entry_guards, entry_guard_t *, entry, + { + if (entry_is_live(entry, 0, 1, 0)) { + if (n++ == options->NumEntryGuards) { + control_event_guard(entry->nickname, entry->identity, "DEFERRED"); + return; + } + } + }); +#endif +} + #define NUM_ENTRY_PICK_TRIES 100 /** Add a new (preferably stable and fast) router to our @@ -1948,6 +1971,8 @@ add_an_entry_guard(routerinfo_t *chosen) smartlist_insert(entry_guards, 0, entry); else /* append */ smartlist_add(entry_guards, entry); + control_event_guard(entry->nickname, entry->identity, "NEW"); + control_event_guard_deferred(); log_entry_guards(LOG_INFO); return router; } @@ -2008,6 +2033,7 @@ remove_dead_entries(void) log_info(LD_CIRC, "Entry guard '%s' (%s) has been down or unlisted " "since %s local time; removing.", entry->nickname, dbuf, tbuf); + control_event_guard(entry->nickname, entry->identity, "DROPPED"); tor_free(entry); smartlist_del_keeporder(entry_guards, i); log_entry_guards(LOG_INFO); @@ -2103,6 +2129,7 @@ entry_guard_register_connect_status(const char *digest, int succeeded, entry->nickname, buf); entry->unreachable_since = 0; entry->last_attempted = now; + control_event_guard(entry->nickname, entry->identity, "UP"); changed = 1; } if (!entry->made_contact) { @@ -2125,6 +2152,7 @@ entry_guard_register_connect_status(const char *digest, int succeeded, log_info(LD_CIRC, "Unable to connect to entry guard '%s' (%s). " "Marking as unreachable.", entry->nickname, buf); entry->unreachable_since = entry->last_attempted = now; + control_event_guard(entry->nickname, entry->identity, "DOWN"); changed = 1; } else { char tbuf[ISO_TIME_LEN+1]; diff --git a/src/or/control.c b/src/or/control.c index f5b0d5223f..90ab2ca0cc 100644 --- a/src/or/control.c +++ b/src/or/control.c @@ -86,7 +86,8 @@ const char control_c_id[] = #define EVENT_STATUS_CLIENT 0x0010 #define EVENT_STATUS_SERVER 0x0011 #define EVENT_STATUS_GENERAL 0x0012 -#define _EVENT_MAX 0x0012 +#define EVENT_GUARD 0x0013 +#define _EVENT_MAX 0x0013 /* If _EVENT_MAX ever hits 0x0020, we need to make the mask wider. */ /** Array mapping from message type codes to human-readable message @@ -1064,6 +1065,8 @@ handle_control_setevents(control_connection_t *conn, uint32_t len, event_code = EVENT_STATUS_CLIENT; else if (!strcasecmp(ev, "STATUS_SERVER")) event_code = EVENT_STATUS_SERVER; + else if (!strcasecmp(ev, "GUARD")) + event_code = EVENT_GUARD; else { connection_printf_to_buf(conn, "552 Unrecognized event \"%s\"\r\n", ev); @@ -3650,6 +3653,34 @@ control_event_server_status(int severity, const char *format, ...) return r; } +/** DOCDOC */ +int +control_event_guard(const char *nickname, const char *digest, + const char *status) +{ + char hbuf[HEX_DIGEST_LEN+1]; + base16_encode(hbuf, sizeof(hbuf), digest, DIGEST_LEN); + if (!EVENT_IS_INTERESTING1(EVENT_GUARD)) + return 0; + + if (EVENT_IS_INTERESTING1L(EVENT_GUARD)) { + char buf[MAX_VERBOSE_NICKNAME_LEN+1]; + routerinfo_t *ri = router_get_by_digest(digest); + if (ri) { + router_get_verbose_nickname(buf, ri); + } else { + tor_snprintf(buf, sizeof(buf), "$%s~%s", hbuf, nickname); + } + send_control1_event(EVENT_GUARD, LONG_NAMES, + "650 GUARD ENTRY %s %s\r\n", buf, status); + } + if (EVENT_IS_INTERESTING1S(EVENT_GUARD)) { + send_control1_event(EVENT_GUARD, SHORT_NAMES, + "650 GUARD ENTRY $%s %s\r\n", hbuf, status); + } + 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. */ diff --git a/src/or/or.h b/src/or/or.h index 0281af2c6e..035787a1a5 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -2202,6 +2202,8 @@ int control_event_client_status(int severity, const char *format, ...) CHECK_PRINTF(2,3); int control_event_server_status(int severity, const char *format, ...) CHECK_PRINTF(2,3); +int control_event_guard(const char *nickname, const char *digest, + const char *status); int init_cookie_authentication(int enabled); int decode_hashed_password(char *buf, const char *hashed);