diff options
Diffstat (limited to 'src/or/control.c')
-rw-r--r-- | src/or/control.c | 294 |
1 files changed, 271 insertions, 23 deletions
diff --git a/src/or/control.c b/src/or/control.c index c76ade06d5..de24294efc 100644 --- a/src/or/control.c +++ b/src/or/control.c @@ -36,17 +36,14 @@ #include "networkstatus.h" #include "nodelist.h" #include "policies.h" -#include "rendcommon.h" -#include "rendservice.h" #include "reasons.h" #include "rendclient.h" #include "rendcommon.h" +#include "rendservice.h" #include "rephist.h" #include "router.h" #include "routerlist.h" #include "routerparse.h" -#include "rendclient.h" -#include "rendcommon.h" #ifndef _WIN32 #include <pwd.h> @@ -170,6 +167,8 @@ static int handle_control_usefeature(control_connection_t *conn, const char *body); static int handle_control_hsfetch(control_connection_t *conn, uint32_t len, const char *body); +static int handle_control_hspost(control_connection_t *conn, uint32_t len, + const char *body); static int handle_control_add_onion(control_connection_t *conn, uint32_t len, const char *body); static int handle_control_del_onion(control_connection_t *conn, uint32_t len, @@ -1744,7 +1743,7 @@ getinfo_helper_dir(control_connection_t *control_conn, return -1; } - if (rend_cache_lookup_entry(question, -1, &e) > 0) { + if (!rend_cache_lookup_entry(question, -1, &e)) { /* Descriptor found in cache */ *answer = tor_strdup(e->desc); } else { @@ -3448,6 +3447,101 @@ handle_control_hsfetch(control_connection_t *conn, uint32_t len, return 0; } +/** Implementation for the HSPOST command. */ +static int +handle_control_hspost(control_connection_t *conn, + uint32_t len, + const char *body) +{ + static const char *opt_server = "SERVER="; + smartlist_t *args = smartlist_new(); + smartlist_t *hs_dirs = NULL; + const char *encoded_desc = body; + size_t encoded_desc_len = len; + + char *cp = memchr(body, '\n', len); + char *argline = tor_strndup(body, cp-body); + + /* If any SERVER= options were specified, try parse the options line */ + if (!strcasecmpstart(argline, opt_server)) { + /* encoded_desc begins after a newline character */ + cp = cp + 1; + encoded_desc = cp; + encoded_desc_len = len-(cp-body); + + smartlist_split_string(args, argline, " ", + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); + SMARTLIST_FOREACH_BEGIN(args, const char *, arg) { + if (!strcasecmpstart(arg, opt_server)) { + const char *server = arg + strlen(opt_server); + const node_t *node = node_get_by_hex_id(server); + + if (!node || !node->rs) { + connection_printf_to_buf(conn, "552 Server \"%s\" not found\r\n", + server); + goto done; + } + if (!node->rs->is_hs_dir) { + connection_printf_to_buf(conn, "552 Server \"%s\" is not a HSDir" + "\r\n", server); + goto done; + } + /* Valid server, add it to our local list. */ + if (!hs_dirs) + hs_dirs = smartlist_new(); + smartlist_add(hs_dirs, node->rs); + } else { + connection_printf_to_buf(conn, "512 Unexpected argument \"%s\"\r\n", + arg); + goto done; + } + } SMARTLIST_FOREACH_END(arg); + } + + /* Read the dot encoded descriptor, and parse it. */ + rend_encoded_v2_service_descriptor_t *desc = + tor_malloc_zero(sizeof(rend_encoded_v2_service_descriptor_t)); + read_escaped_data(encoded_desc, encoded_desc_len, &desc->desc_str); + + rend_service_descriptor_t *parsed = NULL; + char *intro_content = NULL; + size_t intro_size; + size_t encoded_size; + const char *next_desc; + if (!rend_parse_v2_service_descriptor(&parsed, desc->desc_id, &intro_content, + &intro_size, &encoded_size, + &next_desc, desc->desc_str, 1)) { + /* Post the descriptor. */ + char serviceid[REND_SERVICE_ID_LEN_BASE32+1]; + if (!rend_get_service_id(parsed->pk, serviceid)) { + smartlist_t *descs = smartlist_new(); + smartlist_add(descs, desc); + + /* We are about to trigger HS descriptor upload so send the OK now + * because after that 650 event(s) are possible so better to have the + * 250 OK before them to avoid out of order replies. */ + send_control_done(conn); + + /* Trigger the descriptor upload */ + directory_post_to_hs_dir(parsed, descs, hs_dirs, serviceid, 0); + smartlist_free(descs); + } + + rend_service_descriptor_free(parsed); + } else { + connection_printf_to_buf(conn, "554 Invalid descriptor\r\n"); + } + + tor_free(intro_content); + rend_encoded_v2_service_descriptor_free(desc); + done: + tor_free(argline); + smartlist_free(hs_dirs); /* Contents belong to the rend service code. */ + SMARTLIST_FOREACH(args, char *, arg, tor_free(arg)); + smartlist_free(args); + return 0; +} + /** Called when we get a ADD_ONION command; parse the body, and set up * the new ephemeral Onion Service. */ static int @@ -3709,12 +3803,17 @@ add_onion_helper_keyarg(const char *arg, int discard_pk, memwipe(cp, 0, strlen(cp)); tor_free(cp); }); + smartlist_free(key_args); if (!ok) { crypto_pk_free(pk); pk = NULL; } - if (err_msg_out) *err_msg_out = err_msg; + if (err_msg_out) { + *err_msg_out = err_msg; + } else { + tor_free(err_msg); + } *key_new_alg_out = key_new_alg; *key_new_blob_out = key_new_blob; @@ -4099,6 +4198,9 @@ connection_control_process_inbuf(control_connection_t *conn) } else if (!strcasecmp(conn->incoming_cmd, "HSFETCH")) { if (handle_control_hsfetch(conn, cmd_data_len, args)) return -1; + } else if (!strcasecmp(conn->incoming_cmd, "+HSPOST")) { + if (handle_control_hspost(conn, cmd_data_len, args)) + return -1; } else if (!strcasecmp(conn->incoming_cmd, "ADD_ONION")) { int ret = handle_control_add_onion(conn, cmd_data_len, args); memwipe(args, 0, cmd_data_len); /* Scrub the private key. */ @@ -5872,6 +5974,69 @@ control_event_hs_descriptor_requested(const rend_data_t *rend_query, desc_id_base32); } +/** For an HS descriptor query <b>rend_data</b>, using the + * <b>onion_address</b> and HSDir fingerprint <b>hsdir_fp</b>, find out + * which descriptor ID in the query is the right one. + * + * Return a pointer of the binary descriptor ID found in the query's object + * or NULL if not found. */ +static const char * +get_desc_id_from_query(const rend_data_t *rend_data, const char *hsdir_fp) +{ + int replica; + const char *desc_id = NULL; + + /* Possible if the fetch was done using a descriptor ID. This means that + * the HSFETCH command was used. */ + if (!tor_digest_is_zero(rend_data->desc_id_fetch)) { + desc_id = rend_data->desc_id_fetch; + goto end; + } + + /* OK, we have an onion address so now let's find which descriptor ID + * is the one associated with the HSDir fingerprint. */ + for (replica = 0; replica < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS; + replica++) { + const char *digest = rend_data->descriptor_id[replica]; + + SMARTLIST_FOREACH_BEGIN(rend_data->hsdirs_fp, char *, fingerprint) { + if (tor_memcmp(fingerprint, hsdir_fp, DIGEST_LEN) == 0) { + /* Found it! This descriptor ID is the right one. */ + desc_id = digest; + goto end; + } + } SMARTLIST_FOREACH_END(fingerprint); + } + +end: + return desc_id; +} + +/** send HS_DESC upload event. + * + * <b>service_id</b> is the descriptor onion address. + * <b>hs_dir</b> is the description of contacting hs directory. + * <b>desc_id_base32</b> is the ID of requested hs descriptor. + */ +void +control_event_hs_descriptor_upload(const char *service_id, + const char *id_digest, + const char *desc_id_base32) +{ + if (!service_id || !id_digest || !desc_id_base32) { + log_warn(LD_BUG, "Called with service_digest==%p, " + "desc_id_base32==%p, id_digest==%p", service_id, + desc_id_base32, id_digest); + return; + } + + send_control_event(EVENT_HS_DESC, ALL_FORMATS, + "650 HS_DESC UPLOAD %s UNKNOWN %s %s\r\n", + service_id, + node_describe_longname_by_id(id_digest), + desc_id_base32); +} + /** send HS_DESC event after got response from hs directory. * * NOTE: this is an internal function used by following functions: @@ -5883,27 +6048,76 @@ control_event_hs_descriptor_requested(const rend_data_t *rend_query, void control_event_hs_descriptor_receive_end(const char *action, const char *onion_address, - rend_auth_type_t auth_type, + const rend_data_t *rend_data, const char *id_digest, const char *reason) { + char *desc_id_field = NULL; char *reason_field = NULL; + char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1]; + const char *desc_id = NULL; - if (!action || !id_digest || !onion_address) { - log_warn(LD_BUG, "Called with action==%p, id_digest==%p " - "onion_address==%p", action, id_digest, onion_address); + if (!action || !id_digest || !rend_data || !onion_address) { + log_warn(LD_BUG, "Called with action==%p, id_digest==%p, " + "rend_data==%p, onion_address==%p", action, id_digest, + rend_data, onion_address); return; } + desc_id = get_desc_id_from_query(rend_data, id_digest); + if (desc_id != NULL) { + /* Set the descriptor ID digest to base32 so we can send it. */ + base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_id, + DIGEST_LEN); + /* Extra whitespace is needed before the value. */ + tor_asprintf(&desc_id_field, " %s", desc_id_base32); + } + if (reason) { tor_asprintf(&reason_field, " REASON=%s", reason); } send_control_event(EVENT_HS_DESC, ALL_FORMATS, - "650 HS_DESC %s %s %s %s%s\r\n", + "650 HS_DESC %s %s %s %s%s%s\r\n", action, rend_hsaddress_str_or_unknown(onion_address), - rend_auth_type_to_string(auth_type), + rend_auth_type_to_string(rend_data->auth_type), + node_describe_longname_by_id(id_digest), + desc_id_field ? desc_id_field : "", + reason_field ? reason_field : ""); + + tor_free(desc_id_field); + tor_free(reason_field); +} + +/** send HS_DESC event after got response from hs directory. + * + * NOTE: this is an internal function used by following functions: + * control_event_hs_descriptor_uploaded + * control_event_hs_descriptor_upload_failed + * + * So do not call this function directly. + */ +void +control_event_hs_descriptor_upload_end(const char *action, + const char *id_digest, + const char *reason) +{ + char *reason_field = NULL; + + if (!action || !id_digest) { + log_warn(LD_BUG, "Called with action==%p, id_digest==%p", action, + id_digest); + return; + } + + if (reason) { + tor_asprintf(&reason_field, " REASON=%s", reason); + } + + send_control_event(EVENT_HS_DESC, ALL_FORMATS, + "650 HS_DESC %s UNKNOWN UNKNOWN %s%s\r\n", + action, node_describe_longname_by_id(id_digest), reason_field ? reason_field : ""); @@ -5912,19 +6126,35 @@ control_event_hs_descriptor_receive_end(const char *action, /** send HS_DESC RECEIVED event * - * called when a we successfully received a hidden service descriptor. + * called when we successfully received a hidden service descriptor. */ void control_event_hs_descriptor_received(const char *onion_address, - rend_auth_type_t auth_type, + const rend_data_t *rend_data, const char *id_digest) { - if (!id_digest) { - log_warn(LD_BUG, "Called with id_digest==%p", id_digest); + if (!rend_data || !id_digest || !onion_address) { + log_warn(LD_BUG, "Called with rend_data==%p, id_digest==%p, " + "onion_address==%p", rend_data, id_digest, onion_address); return; } control_event_hs_descriptor_receive_end("RECEIVED", onion_address, - auth_type, id_digest, NULL); + rend_data, id_digest, NULL); +} + +/** send HS_DESC UPLOADED event + * + * called when we successfully uploaded a hidden service descriptor. + */ +void +control_event_hs_descriptor_uploaded(const char *id_digest) +{ + if (!id_digest) { + log_warn(LD_BUG, "Called with id_digest==%p", + id_digest); + return; + } + control_event_hs_descriptor_upload_end("UPLOADED", id_digest, NULL); } /** Send HS_DESC event to inform controller that query <b>rend_query</b> @@ -5933,17 +6163,18 @@ control_event_hs_descriptor_received(const char *onion_address, * field. */ void -control_event_hs_descriptor_failed(const char *onion_address, - rend_auth_type_t auth_type, +control_event_hs_descriptor_failed(const rend_data_t *rend_data, const char *id_digest, const char *reason) { - if (!id_digest) { - log_warn(LD_BUG, "Called with id_digest==%p", id_digest); + if (!rend_data || !id_digest) { + log_warn(LD_BUG, "Called with rend_data==%p, id_digest==%p", + rend_data, id_digest); return; } - control_event_hs_descriptor_receive_end("FAILED", onion_address, auth_type, - id_digest, reason); + control_event_hs_descriptor_receive_end("FAILED", + rend_data->onion_address, + rend_data, id_digest, reason); } /** send HS_DESC_CONTENT event after completion of a successful fetch from @@ -5979,6 +6210,23 @@ control_event_hs_descriptor_content(const char *onion_address, tor_free(esc_content); } +/** Send HS_DESC event to inform controller upload of hidden service + * descriptor identified by <b>id_digest</b> failed. If <b>reason</b> + * is not NULL, add it to REASON= field. + */ +void +control_event_hs_descriptor_upload_failed(const char *id_digest, + const char *reason) +{ + if (!id_digest) { + log_warn(LD_BUG, "Called with id_digest==%p", + id_digest); + return; + } + control_event_hs_descriptor_upload_end("UPLOAD_FAILED", + id_digest, reason); +} + /** Free any leftover allocated memory of the control.c subsystem. */ void control_free_all(void) |