prop224: Directory support for v3 descriptor publishing

Closes #19205

Signed-off-by: David Goulet <dgoulet@torproject.org>
Signed-off-by: George Kadianakis <desnacked@riseup.net>
This commit is contained in:
David Goulet 2016-08-11 15:21:54 -04:00
parent 1aeaba4906
commit 45a72356cb
5 changed files with 168 additions and 2 deletions

View File

@ -16,6 +16,7 @@
#include "dirvote.h"
#include "entrynodes.h"
#include "geoip.h"
#include "hs_cache.h"
#include "hs_common.h"
#include "main.h"
#include "microdesc.h"
@ -3443,6 +3444,90 @@ handle_get_robots(dir_connection_t *conn, const get_handler_args_t *args)
return 0;
}
/* Given the <b>url</b> from a POST request, try to extract the version number
* using the provided <b>prefix</b>. The version should be after the prefix and
* ending with the seperator "/". For instance:
* /tor/hs/3/publish
*
* On success, <b>end_pos</b> points to the position right after the version
* was found. On error, it is set to NULL.
*
* Return version on success else negative value. */
STATIC int
parse_hs_version_from_post(const char *url, const char *prefix,
const char **end_pos)
{
int ok;
unsigned long version;
const char *start;
char *end = NULL;
tor_assert(url);
tor_assert(prefix);
tor_assert(end_pos);
/* Check if the prefix does start the url. */
if (strcmpstart(url, prefix)) {
goto err;
}
/* Move pointer to the end of the prefix string. */
start = url + strlen(prefix);
/* Try this to be the HS version and if we are still at the separator, next
* will be move to the right value. */
version = tor_parse_long(start, 10, 0, INT_MAX, &ok, &end);
if (!ok) {
goto err;
}
*end_pos = end;
return (int) version;
err:
*end_pos = NULL;
return -1;
}
/* Handle the POST request for a hidden service descripror. The request is in
* <b>url</b>, the body of the request is in <b>body</b>. Return 200 on success
* else return 400 indicating a bad request. */
static int
handle_post_hs_descriptor(const char *url, const char *body)
{
int version;
const char *end_pos;
tor_assert(url);
tor_assert(body);
version = parse_hs_version_from_post(url, "/tor/hs/", &end_pos);
if (version < 0) {
goto err;
}
/* We have a valid version number, now make sure it's a publish request. Use
* the end position just after the version and check for the command. */
if (strcmpstart(end_pos, "/publish")) {
goto err;
}
switch (version) {
case HS_VERSION_THREE:
if (hs_cache_store_as_dir(body) < 0) {
goto err;
}
log_info(LD_REND, "Publish request for HS descriptor handled "
"successfully.");
break;
default:
/* Unsupported version, return a bad request. */
goto err;
}
return 200;
err:
/* Bad request. */
return 400;
}
/** Helper function: called when a dirserver gets a complete HTTP POST
* request. Look for an uploaded server descriptor or rendezvous
* service descriptor. On finding one, process it and write a
@ -3487,6 +3572,20 @@ directory_handle_command_post(dir_connection_t *conn, const char *headers,
goto done;
}
/* Handle HS descriptor publish request. */
/* XXX: This should be disabled with a consensus param until we want to
* the prop224 be deployed and thus use. */
if (connection_dir_is_encrypted(conn) && !strcmpstart(url, "/tor/hs/")) {
const char *msg = "HS descriptor stored successfully.";
/* We most probably have a publish request for an HS descriptor. */
int code = handle_post_hs_descriptor(url, body);
if (code != 200) {
msg = "Invalid HS descriptor. Rejected.";
}
write_http_status_line(conn, code, msg);
goto done;
}
if (!authdir_mode(options)) {
/* we just provide cached directories; we don't want to
* receive anything. */

View File

@ -160,6 +160,9 @@ STATIC void find_dl_min_and_max_delay(download_status_t *dls,
int *min, int *max);
STATIC int next_random_exponential_delay(int delay, int max_delay);
STATIC int parse_hs_version_from_post(const char *url, const char *prefix,
const char **end_pos);
#endif
#endif

View File

@ -249,7 +249,7 @@ hs_cache_store_as_dir(const char *desc)
* we are sure that the descriptor's version is supported else the
* decoding would have failed. */
switch (dir_desc->plaintext_data->version) {
case 3:
case HS_VERSION_THREE:
default:
if (cache_store_v3_as_dir(dir_desc) < 0) {
goto err;
@ -279,7 +279,7 @@ hs_cache_lookup_as_dir(uint32_t version, const char *query,
tor_assert(hs_desc_is_supported_version(version));
switch (version) {
case 3:
case HS_VERSION_THREE:
default:
found = cache_lookup_v3_as_dir(query, desc_out);
break;

View File

@ -14,6 +14,8 @@
/* Protocol version 2. Use this instead of hardcoding "2" in the code base,
* this adds a clearer semantic to the value when used. */
#define HS_VERSION_TWO 2
/* Version 3 of the protocol (prop224). */
#define HS_VERSION_THREE 3
void rend_data_free(rend_data_t *data);
rend_data_t *rend_data_dup(const rend_data_t *data);

View File

@ -5345,6 +5345,67 @@ test_dir_find_dl_schedule(void* data)
mock_options = NULL;
}
static void
test_dir_post_parsing(void *arg)
{
(void) arg;
/* Test the version parsing from an HS descriptor publish request. */
{
const char *end;
const char *prefix = "/tor/hs/";
int version = parse_hs_version_from_post("/tor/hs//publish", prefix, &end);
tt_int_op(version, OP_EQ, -1);
tt_ptr_op(end, OP_EQ, NULL);
version = parse_hs_version_from_post("/tor/hs/a/publish", prefix, &end);
tt_int_op(version, OP_EQ, -1);
tt_ptr_op(end, OP_EQ, NULL);
version = parse_hs_version_from_post("/tor/hs/3/publish", prefix, &end);
tt_int_op(version, OP_EQ, 3);
tt_str_op(end, OP_EQ, "/publish");
version = parse_hs_version_from_post("/tor/hs/42/publish", prefix, &end);
tt_int_op(version, OP_EQ, 42);
tt_str_op(end, OP_EQ, "/publish");
version = parse_hs_version_from_post("/tor/hs/18163/publish", prefix, &end);
tt_int_op(version, OP_EQ, 18163);
tt_str_op(end, OP_EQ, "/publish");
version = parse_hs_version_from_post("JUNKJUNKJUNK", prefix, &end);
tt_int_op(version, OP_EQ, -1);
tt_ptr_op(end, OP_EQ, NULL);
version = parse_hs_version_from_post("/tor/hs/3/publish", "blah", &end);
tt_int_op(version, OP_EQ, -1);
tt_ptr_op(end, OP_EQ, NULL);
/* Missing the '/' at the end of the prefix. */
version = parse_hs_version_from_post("/tor/hs/3/publish", "/tor/hs", &end);
tt_int_op(version, OP_EQ, -1);
tt_ptr_op(end, OP_EQ, NULL);
version = parse_hs_version_from_post("/random/blah/tor/hs/3/publish",
prefix, &end);
tt_int_op(version, OP_EQ, -1);
tt_ptr_op(end, OP_EQ, NULL);
version = parse_hs_version_from_post("/tor/hs/3/publish/random/junk",
prefix, &end);
tt_int_op(version, OP_EQ, 3);
tt_str_op(end, OP_EQ, "/publish/random/junk");
version = parse_hs_version_from_post("/tor/hs/-1/publish", prefix, &end);
tt_int_op(version, OP_EQ, -1);
tt_ptr_op(end, OP_EQ, NULL);
/* INT_MAX */
version = parse_hs_version_from_post("/tor/hs/2147483647/publish",
prefix, &end);
tt_int_op(version, OP_EQ, INT_MAX);
tt_str_op(end, OP_EQ, "/publish");
/* INT_MAX + 1*/
version = parse_hs_version_from_post("/tor/hs/2147483648/publish",
prefix, &end);
tt_int_op(version, OP_EQ, -1);
tt_ptr_op(end, OP_EQ, NULL);
}
done:
;
}
#define DIR_LEGACY(name) \
{ #name, test_dir_ ## name , TT_FORK, NULL, NULL }
@ -5378,6 +5439,7 @@ struct testcase_t dir_tests[] = {
DIR(fmt_control_ns, 0),
DIR(dirserv_set_routerstatus_testing, 0),
DIR(http_handling, 0),
DIR(post_parsing, 0),
DIR(purpose_needs_anonymity, 0),
DIR(fetch_type, 0),
DIR(packages, 0),