Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also .

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also .
base repository: DonnchaC/tor
base: ca03b10b0c39a02fd66824d04deccf40cbd66951
head repository: DonnchaC/tor
compare: 3523
  • 8 commits
  • 5 files changed
  • 0 comments
  • 1 contributor
Commits on Mar 27, 2015
A number of objects in handle_control_hspost() are now freed
correctly when finishing. directory_post_to_hs_dir() is fixed
to prevent leaking of a smartlist_t when hs_dirs != NULL.

smartlist_t *hs_dirs is now always freed in handle_control_hspost()
rather than in directory_post_to_hs_dir().
Showing with 246 additions and 17 deletions.
  1. +198 −1 src/or/control.c
  2. +12 −3 src/or/control.h
  3. +6 −0 src/or/directory.c
  4. +26 −13 src/or/rendservice.c
  5. +4 −0 src/or/rendservice.h
@@ -37,6 +37,8 @@
#include "nodelist.h"
#include "policies.h"
#include "reasons.h"
#include "rendcommon.h"
#include "rendservice.h"
#include "rephist.h"
#include "router.h"
#include "routerlist.h"
@@ -157,6 +159,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_hspost(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,
@@ -3211,6 +3215,105 @@ handle_control_dropguards(control_connection_t *conn,
return 0;
}

/** Implementation for the HSPOST command. */
static int
handle_control_hspost(control_connection_t *conn,
uint32_t len,
const char *body)
{
rend_service_descriptor_t *parsed = NULL;
rend_encoded_v2_service_descriptor_t *desc =
tor_malloc_zero(sizeof(rend_encoded_v2_service_descriptor_t));
char *cp;
char *intro_content;
size_t intro_size;
size_t encoded_size;
const char *next_desc;
char serviceid[REND_SERVICE_ID_LEN_BASE32+1];

smartlist_t *args = smartlist_new();
smartlist_t *hs_dirs = NULL;
smartlist_t *descs = smartlist_new();
static const char *opt_server = "SERVER=";

/* If any SERVER= options were specified, try parse the options line */
if (!strcasecmpstart(body, opt_server)) {
/* Set cp to start of the descriptor content */
cp = memchr(body, '\n', len);
*cp++ = '\0';

/* Control command can accept 0 or more arguments */
args = getargs_helper("+HSPOST", conn, body, 0, -1);

/** Parse each server fingeprint from the options **/
SMARTLIST_FOREACH_BEGIN(args, const char *, arg) {
const node_t *node;

if (!strcasecmpstart(arg, opt_server)) {
const char *server;
server = arg + strlen(opt_server);

node = node_get_by_hex_id(server);
if (!node) {
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, "552 Unexpected argument \"%s\"\r\n",
arg);
goto done;
}
} SMARTLIST_FOREACH_END(arg);
} else {
/* No options were specified, descriptor should begin on the first line */
cp = (char*) body;
}

read_escaped_data(cp, len-(cp-body), &desc->desc_str);

/* Check that the descriptor can be parsed */
if (rend_parse_v2_service_descriptor(&parsed, desc->desc_id, &intro_content,
&intro_size, &encoded_size,
&next_desc, desc->desc_str, 1) < 0) {
connection_printf_to_buf(conn, "554 Invalid descriptor\r\n");
goto done;
}

/* We don't care about the introduction points. */
tor_free(intro_content);
smartlist_add(descs, desc);
rend_get_service_id(parsed->pk, serviceid);

/* 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);

done:
SMARTLIST_FOREACH(args, char *, arg, tor_free(arg));
smartlist_free(args);
/** Don't free hsdir items as they are routerstatus entries */
smartlist_free(hs_dirs);
rend_service_descriptor_free(parsed);
for (int i = 0; i < smartlist_len(descs); i++)
rend_encoded_v2_service_descriptor_free(smartlist_get(descs, i));
smartlist_free(descs);
return 0;
}

/** Called when <b>conn</b> has no more bytes left on its outbuf. */
int
connection_control_finished_flushing(control_connection_t *conn)
@@ -3508,6 +3611,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, "+HSPOST")) {
if (handle_control_hspost(conn, cmd_data_len, args))
return -1;
} else {
connection_printf_to_buf(conn, "510 Unrecognized command \"%s\"\r\n",
conn->incoming_cmd);
@@ -5202,6 +5308,31 @@ control_event_hs_descriptor_requested(const rend_data_t *rend_query,
desc_id_base32);
}

/** 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 %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:
@@ -5239,9 +5370,43 @@ control_event_hs_descriptor_receive_end(const char *action,
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 %s%s\r\n",
action,
node_describe_longname_by_id(id_digest),
reason_field ? reason_field : "");

tor_free(reason_field);
}

/** 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 rend_data_t *rend_query,
@@ -5256,6 +5421,21 @@ control_event_hs_descriptor_received(const rend_data_t *rend_query,
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>
* failed to retrieve hidden service descriptor identified by
* <b>id_digest</b>. If <b>reason</b> is not NULL, add it to REASON=
@@ -5275,6 +5455,23 @@ control_event_hs_descriptor_failed(const rend_data_t *rend_query,
id_digest, reason);
}

/** 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)
@@ -106,15 +106,24 @@ MOCK_DECL(const char *, node_describe_longname_by_id,(const char *id_digest));
void control_event_hs_descriptor_requested(const rend_data_t *rend_query,
const char *desc_id_base32,
const char *hs_dir);
void control_event_hs_descriptor_upload(const char *service_id,
const char *desc_id_base32,
const char *hs_dir);
void control_event_hs_descriptor_receive_end(const char *action,
const rend_data_t *rend_query,
const char *hs_dir,
const char *reason);
const rend_data_t *rend_query,
const char *hs_dir,
const char *reason);
void control_event_hs_descriptor_upload_end(const char *action,
const char *hs_dir,
const char *reason);
void control_event_hs_descriptor_received(const rend_data_t *rend_query,
const char *hs_dir);
void control_event_hs_descriptor_uploaded(const char *hs_dir);
void control_event_hs_descriptor_failed(const rend_data_t *rend_query,
const char *hs_dir,
const char *reason);
void control_event_hs_descriptor_upload_failed(const char *hs_dir,
const char *reason);

void control_free_all(void);

@@ -2157,6 +2157,9 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
}

if (conn->base_.purpose == DIR_PURPOSE_UPLOAD_RENDDESC_V2) {
#define SEND_HS_DESC_UPLOAD_FAILED_EVENT(reason) ( \
control_event_hs_descriptor_upload_failed(conn->identity_digest, \
reason) )
log_info(LD_REND,"Uploaded rendezvous descriptor (status %d "
"(%s))",
status_code, escaped(reason));
@@ -2165,17 +2168,20 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
log_info(LD_REND,
"Uploading rendezvous descriptor: finished with status "
"200 (%s)", escaped(reason));
control_event_hs_descriptor_uploaded(conn->identity_digest);
break;
case 400:
log_warn(LD_REND,"http status 400 (%s) response from dirserver "
"'%s:%d'. Malformed rendezvous descriptor?",
escaped(reason), conn->base_.address, conn->base_.port);
SEND_HS_DESC_UPLOAD_FAILED_EVENT("UPLOAD_REJECTED");
break;
default:
log_warn(LD_REND,"http status %d (%s) response unexpected (server "
"'%s:%d').",
status_code, escaped(reason), conn->base_.address,
conn->base_.port);
SEND_HS_DESC_UPLOAD_FAILED_EVENT("UNEXPECTED");
break;
}
}

No commit comments for this range