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: 3234-patch
  • 13 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 245 additions and 17 deletions.
  1. +194 −1 src/or/control.c
  2. +12 −3 src/or/control.h
  3. +6 −0 src/or/directory.c
  4. +29 −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,101 @@ 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)
{
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) {
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 <b>conn</b> has no more bytes left on its outbuf. */
int
connection_control_finished_flushing(control_connection_t *conn)
@@ -3508,6 +3607,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 +5304,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 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:
@@ -5239,9 +5366,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 UNKNOWN UNKNOWN %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 +5417,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 +5451,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