diff --git a/src/or/config.c b/src/or/config.c index 39b85aa..ff42d27 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -1096,6 +1096,8 @@ options_act_reversible(const or_options_t *old_options, char **msg) "non-control network connections. Shutting down all existing " "connections."); connection_mark_all_noncontrol_connections(); + /* We can't complete circuits until the network is re-enabled. */ + can_complete_circuit = 0; } } diff --git a/src/or/control.c b/src/or/control.c index 9378f38..17d2a46 100644 --- a/src/or/control.c +++ b/src/or/control.c @@ -37,6 +37,8 @@ #include "nodelist.h" #include "policies.h" #include "reasons.h" +#include "rendclient.h" +#include "rendcommon.h" #include "rephist.h" #include "router.h" #include "routerlist.h" @@ -156,6 +158,8 @@ static int handle_control_resolve(control_connection_t *conn, uint32_t len, static int handle_control_usefeature(control_connection_t *conn, uint32_t len, const char *body); +static int handle_control_forgeths(control_connection_t *conn, uint32_t len, + const char *body); static int write_stream_target_to_buf(entry_connection_t *conn, char *buf, size_t len); static void orconn_target_get_name(char *buf, size_t len, @@ -3164,6 +3168,33 @@ handle_control_dropguards(control_connection_t *conn, return 0; } +/** Called when we get a FORGETHS command: parse the hidden service's onion + * address and purge any cached state related to the service. */ +static int +handle_control_forgeths(control_connection_t *conn, uint32_t len, + const char *body) +{ + smartlist_t *args; + char *onion_address; + + args = getargs_helper("FORGETHS", conn, body, 1, 1); + if (!args) + return -1; + onion_address = smartlist_get(args, 0); + smartlist_free(args); + + if (!rend_valid_service_id(onion_address)) { + connection_write_str_to_buf("513 Invalid hidden service address\r\n", conn); + tor_free(onion_address); + return -1; + } + + rend_client_purge_hidden_service(onion_address); + tor_free(onion_address); + send_control_done(conn); + return 0; +} + /** Called when <b>conn</b> has no more bytes left on its outbuf. */ int connection_control_finished_flushing(control_connection_t *conn) @@ -3461,6 +3492,9 @@ connection_control_process_inbuf(control_connection_t *conn) } else if (!strcasecmp(conn->incoming_cmd, "DROPGUARDS")) { if (handle_control_dropguards(conn, cmd_data_len, args)) return -1; + } else if (!strcasecmp(conn->incoming_cmd, "FORGETHS")) { + if (handle_control_forgeths(conn, cmd_data_len, args)) + return -1; } else { connection_printf_to_buf(conn, "510 Unrecognized command \"%s\"\r\n", conn->incoming_cmd); diff --git a/src/or/rendclient.c b/src/or/rendclient.c index 19a8cef..c17439d 100644 --- a/src/or/rendclient.c +++ b/src/or/rendclient.c @@ -31,6 +31,8 @@ static extend_info_t *rend_client_get_random_intro_impl( const rend_cache_entry_t *rend_query, const int strict, const int warnings); +static void purge_hid_serv_from_last_hid_serv_requests( + const char *onion_address); /** Purge all potentially remotely-detectable state held in the hidden * service client code. Called on SIGNAL NEWNYM. */ @@ -42,6 +44,16 @@ rend_client_purge_state(void) rend_client_purge_last_hid_serv_requests(); } +/** Purge all cached state relating to the given hidden service. */ +void +rend_client_purge_hidden_service(const char *onion_address) +{ + tor_assert(rend_valid_service_id(onion_address)); + + rend_cache_remove_entry(onion_address); + purge_hid_serv_from_last_hid_serv_requests(onion_address); +} + /** Called when we've established a circuit to an introduction point: * send the introduction request. */ void diff --git a/src/or/rendclient.h b/src/or/rendclient.h index 1f731d0..7084aef 100644 --- a/src/or/rendclient.h +++ b/src/or/rendclient.h @@ -13,6 +13,7 @@ #define TOR_RENDCLIENT_H void rend_client_purge_state(void); +void rend_client_purge_hidden_service(const char *onion_address); void rend_client_introcirc_has_opened(origin_circuit_t *circ); void rend_client_rendcirc_has_opened(origin_circuit_t *circ); diff --git a/src/or/rendcommon.c b/src/or/rendcommon.c index a664b5d..70d7283 100644 --- a/src/or/rendcommon.c +++ b/src/or/rendcommon.c @@ -881,6 +881,34 @@ rend_cache_lookup_entry(const char *query, int version, rend_cache_entry_t **e) return 1; } +/** Remove any cached descriptors for <b>service_id/b>. */ +void +rend_cache_remove_entry(const char *service_id) +{ + char key[REND_SERVICE_ID_LEN_BASE32+2]; /* <version><service_id>\0 */ + rend_cache_entry_t *removed; + + tor_assert(rend_valid_service_id(service_id)); + if (!rend_cache) + return; + + tor_snprintf(key, sizeof(key), "2%s", service_id); + removed = (rend_cache_entry_t *)strmap_remove_lc(rend_cache, key); + if (removed) { + log_info(LD_REND, "Removed cached v2 descriptor for service %s.", + safe_str_client(service_id)); + rend_cache_entry_free(removed); + } + + tor_snprintf(key, sizeof(key), "0%s", service_id); + removed = (rend_cache_entry_t *)strmap_remove_lc(rend_cache, key); + if (removed) { + log_info(LD_REND, "Removed cached v0 descriptor for service %s.", + safe_str_client(service_id)); + rend_cache_entry_free(removed); + } +} + /** Lookup the v2 service descriptor with base32-encoded <b>desc_id</b> and * copy the pointer to it to *<b>desc</b>. Return 1 on success, 0 on * well-formed-but-not-found, and -1 on failure. diff --git a/src/or/rendcommon.h b/src/or/rendcommon.h index 07a47ac..0a3160d 100644 --- a/src/or/rendcommon.h +++ b/src/or/rendcommon.h @@ -39,6 +39,7 @@ void rend_cache_free_all(void); int rend_valid_service_id(const char *query); int rend_cache_lookup_entry(const char *query, int version, rend_cache_entry_t **entry_out); +void rend_cache_remove_entry(const char *service_id); int rend_cache_lookup_v2_desc_as_dir(const char *query, const char **desc); /** Return value from rend_cache_store_v2_desc_as_{dir,client}. */ typedef enum { diff --git a/src/or/rendservice.c b/src/or/rendservice.c index a7c1e32..cc9c0f8 100644 --- a/src/or/rendservice.c +++ b/src/or/rendservice.c @@ -16,6 +16,7 @@ #include "circuituse.h" #include "config.h" #include "directory.h" +#include "main.h" #include "networkstatus.h" #include "nodelist.h" #include "rendclient.h" @@ -3033,6 +3034,9 @@ rend_services_introduce(void) time_t now; const or_options_t *options = get_options(); + if (!can_complete_circuit) + return; + intro_nodes = smartlist_new(); now = time(NULL);