Commit e136f00c authored by Nick Mathewson's avatar Nick Mathewson 🎨
Browse files

r16262@catbus: nickm | 2007-10-29 13:21:35 -0400

 Patch from Karsten: Code to act as (and use) v2 hidden service directories.


svn:r12272
parent 6ad71ec3
......@@ -188,6 +188,7 @@ static config_var_t _option_vars[] = {
V(Group, STRING, NULL),
V(HardwareAccel, BOOL, "0"),
V(HashedControlPassword, STRING, NULL),
V(HidServDirectoryV2, BOOL, "0"),
VAR("HiddenServiceDir", LINELIST_S, RendConfigLines, NULL),
VAR("HiddenServiceExcludeNodes", LINELIST_S, RendConfigLines, NULL),
VAR("HiddenServiceNodes", LINELIST_S, RendConfigLines, NULL),
......@@ -286,8 +287,12 @@ static config_var_t _option_vars[] = {
VAR("VersioningAuthoritativeDirectory",BOOL,VersioningAuthoritativeDir, "0"),
V(VirtualAddrNetwork, STRING, "127.192.0.0/10"),
VAR("__AllDirActionsPrivate", BOOL, AllDirActionsPrivate, "0"),
VAR("__ConsiderAllRoutersAsHidServDirectories", BOOL,
__ConsiderAllRoutersAsHidServDirectories, "0"),
VAR("__DisablePredictedCircuits",BOOL,DisablePredictedCircuits, "0"),
VAR("__LeaveStreamsUnattached",BOOL, LeaveStreamsUnattached, "0"),
VAR("__MinUptimeHidServDirectoryV2", INTERVAL,
__MinUptimeHidServDirectoryV2, "24 hours"),
{ NULL, CONFIG_TYPE_OBSOLETE, 0, NULL }
};
......@@ -2688,6 +2693,9 @@ options_validate(or_options_t *old_options, or_options_t *options,
REJECT("HSAuthorityRecordStats is set but we're not running as "
"a hidden service authority.");
if (options->HidServDirectoryV2 && !options->DirPort)
REJECT("Running as hidden service directory, but no DirPort set.");
if (options->ConnLimit <= 0) {
r = tor_snprintf(buf, sizeof(buf),
"ConnLimit must be greater than 0, but was set to %d",
......@@ -2820,6 +2828,12 @@ options_validate(or_options_t *old_options, or_options_t *options,
return -1;
}
if (options->__MinUptimeHidServDirectoryV2 < 0) {
log_warn(LD_CONFIG, "__MinUptimeHidServDirectoryV2 option must be at "
"least 0 seconds. Changing to 0.");
options->__MinUptimeHidServDirectoryV2 = 0;
}
if (options->RendPostPeriod < MIN_REND_POST_PERIOD) {
log(LOG_WARN,LD_CONFIG,"RendPostPeriod option must be at least %d seconds."
" Clipping.", MIN_REND_POST_PERIOD);
......
......@@ -157,6 +157,10 @@ dir_conn_purpose_to_string(int purpose)
return "status vote fetch";
case DIR_PURPOSE_FETCH_DETACHED_SIGNATURES:
return "consensus signature fetch";
case DIR_PURPOSE_FETCH_RENDDESC_V2:
return "hidden-service v2 descriptor fetch";
case DIR_PURPOSE_UPLOAD_RENDDESC_V2:
return "hidden-service v2 descriptor upload";
}
log_warn(LD_BUG, "Called with unknown purpose %d", purpose);
......@@ -422,7 +426,7 @@ directory_get_from_all_authorities(uint8_t dir_purpose,
* upload or download a server or rendezvous
* descriptor. <b>dir_purpose</b> determines what
* kind of directory connection we're launching, and must be one of
* DIR_PURPOSE_{FETCH|UPLOAD}_{DIR|RENDDESC}. <b>router_purpose</b>
* DIR_PURPOSE_{FETCH|UPLOAD}_{DIR|RENDDESC|RENDDESC_V2}. <b>router_purpose</b>
* specifies the descriptor purposes we have in mind (currently only
* used for FETCH_DIR).
*
......@@ -867,12 +871,27 @@ directory_send_command(dir_connection_t *conn,
url = tor_malloc(len);
tor_snprintf(url, len, "/tor/rendezvous/%s", resource);
break;
case DIR_PURPOSE_FETCH_RENDDESC_V2:
tor_assert(resource);
tor_assert(!payload);
tor_assert(strlen(resource) <= REND_DESC_ID_V2_BASE32);
httpcommand = "GET";
len = strlen(resource) + 32;
url = tor_malloc(len);
tor_snprintf(url, len, "/tor/rendezvous2/%s", resource);
break;
case DIR_PURPOSE_UPLOAD_RENDDESC:
tor_assert(!resource);
tor_assert(payload);
httpcommand = "POST";
url = tor_strdup("/tor/rendezvous/publish");
break;
case DIR_PURPOSE_UPLOAD_RENDDESC_V2:
tor_assert(!resource);
tor_assert(payload);
httpcommand = "POST";
url = tor_strdup("/tor/rendezvous2/publish");
break;
default:
tor_assert(0);
return;
......@@ -1721,8 +1740,46 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
}
}
if (conn->_base.purpose == DIR_PURPOSE_UPLOAD_RENDDESC) {
log_info(LD_REND,"Uploaded rendezvous descriptor (status %d (%s))",
if (conn->_base.purpose == DIR_PURPOSE_FETCH_RENDDESC_V2) {
log_info(LD_REND,"Received rendezvous descriptor (size %d, status %d "
"(%s))",
(int)body_len, status_code, escaped(reason));
switch (status_code) {
case 200:
if (rend_cache_store_v2_client(body, NULL) < 0) {
log_warn(LD_REND,"Fetching v2 rendezvous descriptor failed.");
/* alice's ap_stream will notice when connection_mark_for_close
* cleans it up */
} else {
/* success. notify pending connections about this. */
log_info(LD_REND, "Successfully fetched rendezvous descriptor.");
conn->_base.purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC;
rend_client_desc_here(conn->rend_query);
}
break;
case 404:
/* not there. pending connections will be notified when
* connection_mark_for_close cleans it up. */
break;
case 400:
log_warn(LD_REND, "Fetching v2 rendezvous descriptor failed: "
"http status 400 (%s). Dirserver didn't like our "
"v2 rendezvous query?", escaped(reason));
break;
default:
log_warn(LD_REND, "Fetching v2 rendezvous descriptor failed: "
"http status %d (%s) response unexpected while "
"fetching v2 hidden service descriptor (server '%s:%d').",
status_code, escaped(reason), conn->_base.address,
conn->_base.port);
break;
}
}
if (conn->_base.purpose == DIR_PURPOSE_UPLOAD_RENDDESC ||
conn->_base.purpose == DIR_PURPOSE_UPLOAD_RENDDESC_V2) {
log_info(LD_REND,"Uploaded rendezvous descriptor (status %d "
"(%s))",
status_code, escaped(reason));
switch (status_code) {
case 200:
......@@ -2428,6 +2485,32 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers,
goto done;
}
if (options->HidServDirectoryV2 &&
!strcmpstart(url,"/tor/rendezvous2/")) {
/* Handle v2 rendezvous descriptor fetch request. */
char *descp;
const char *query = url + strlen("/tor/rendezvous2/");
if (strlen(query) == REND_DESC_ID_V2_BASE32) {
log_info(LD_REND, "Got a v2 rendezvous descriptor request for ID '%s'",
query);
switch (rend_cache_lookup_v2_dir(query, &descp)) {
case 1: /* valid */
write_http_response_header(conn, strlen(descp), 0, 0);
connection_write_to_buf(descp, strlen(descp), TO_CONN(conn));
break;
case 0: /* well-formed but not present */
write_http_status_line(conn, 404, "Not found");
break;
case -1: /* not well-formed */
write_http_status_line(conn, 400, "Bad request");
break;
}
} else { /* not well-formed */
write_http_status_line(conn, 400, "Bad request");
}
goto done;
}
if (options->HSAuthoritativeDir && !strcmpstart(url,"/tor/rendezvous/")) {
/* rendezvous descriptor fetch */
const char *descp;
......@@ -2546,6 +2629,27 @@ directory_handle_command_post(dir_connection_t *conn, const char *headers,
conn->_base.state = DIR_CONN_STATE_SERVER_WRITING;
if (parse_http_url(headers, &url) < 0) {
write_http_status_line(conn, 400, "Bad request");
return 0;
}
log_debug(LD_DIRSERV,"rewritten url as '%s'.", url);
/* Handle v2 rendezvous service publish request. */
if (options->HidServDirectoryV2 &&
!strcmpstart(url,"/tor/rendezvous2/publish")) {
if (rend_cache_store_v2_dir(body) < 0) {
log_warn(LD_REND, "Rejected rend descriptor (length %d) from %s.",
(int)body_len, conn->_base.address);
write_http_status_line(conn, 400, "Invalid service descriptor rejected");
log_info(LD_REND, "Handled v2 rendezvous descriptor post: rejected");
} else {
write_http_status_line(conn, 200, "Service descriptor stored");
log_info(LD_REND, "Handled v2 rendezvous descriptor post: accepted");
}
goto done;
}
if (!authdir_mode(options)) {
/* we just provide cached directories; we don't want to
* receive anything. */
......@@ -2554,12 +2658,6 @@ directory_handle_command_post(dir_connection_t *conn, const char *headers,
return 0;
}
if (parse_http_url(headers, &url) < 0) {
write_http_status_line(conn, 400, "Bad request");
return 0;
}
log_debug(LD_DIRSERV,"rewritten url as '%s'.", url);
if (authdir_mode_handles_descs(options) &&
!strcmp(url,"/tor/")) { /* server descriptor post */
const char *msg = NULL;
......@@ -2948,3 +3046,105 @@ dir_split_resource_into_fingerprints(const char *resource,
return 0;
}
/** Determine the responsible hidden service directories for
* <b>desc_ids</b> and upload the appropriate descriptor from
* <b>desc_strs</b> to them; each smartlist must contain
* REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS entries; <b>service_id</b> and
* <b>seconds_valid</b> are only passed for logging purposes.*/
/* XXXX020 enable tunneling when available!! */
void
directory_post_to_hs_dir(smartlist_t *desc_ids, smartlist_t *desc_strs,
const char *service_id, int seconds_valid,
smartlist_t *hs_dirs_)
{
int i, j;
smartlist_t *responsible_dirs;
routerinfo_t *hs_dir;
if (smartlist_len(desc_ids) != REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS ||
smartlist_len(desc_strs) != REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS) {
log_warn(LD_REND, "Could not post descriptors to hidden service "
"directories: Illegal number of descriptor "
"IDs/strings");
return;
}
responsible_dirs = smartlist_create();
for (i = 0; i < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS; i++) {
const char *desc_id = smartlist_get(desc_ids, i);
const char *desc_str = smartlist_get(desc_strs, i);
/* Determine responsible dirs. */
if (hid_serv_get_responsible_directories(responsible_dirs, desc_id,
hs_dirs_) < 0) {
log_warn(LD_REND, "Could not determine the responsible hidden service "
"directories to post descriptors to.");
smartlist_free(responsible_dirs);
return;
}
for (j = 0; j < REND_NUMBER_OF_CONSECUTIVE_REPLICAS; j++) {
char desc_id_base32[REND_DESC_ID_V2_BASE32 + 1];
hs_dir = smartlist_get(responsible_dirs, j);
/* Send publish request. */
directory_initiate_command(hs_dir->address, hs_dir->addr,
hs_dir->or_port, hs_dir->dir_port, 0,
hs_dir->cache_info.identity_digest,
DIR_PURPOSE_UPLOAD_RENDDESC_V2,
ROUTER_PURPOSE_GENERAL,
1, NULL, desc_str, strlen(desc_str), 0);
base32_encode(desc_id_base32, REND_DESC_ID_V2_BASE32 + 1,
desc_id, DIGEST_LEN);
log_info(LD_REND, "Sending publish request for v2 descriptor for "
"service '%s' with descriptor ID '%s' with validity "
"of %d seconds to hidden service directory '%s' on "
"port %d.",
service_id,
desc_id_base32,
seconds_valid,
hs_dir->nickname,
hs_dir->dir_port);
}
smartlist_clear(responsible_dirs);
}
smartlist_free(responsible_dirs);
}
/** Determine the responsible hidden service directories for <b>desc_id</b>
* and fetch the descriptor belonging to this ID from one of them;
* <b>query</b> is only passed for pretty log statements.
* XXXX020 enable tunneling when available!! */
void
directory_get_from_hs_dir(const char *desc_id, const char *query,
smartlist_t *hs_dirs_)
{
smartlist_t *responsible_dirs = smartlist_create();
routerinfo_t *hs_dir;
char desc_id_base32[REND_DESC_ID_V2_BASE32 + 1];
int replica;
tor_assert(desc_id);
tor_assert(query);
tor_assert(strlen(query) == REND_SERVICE_ID_LEN);
/* Determine responsible dirs. */
if (hid_serv_get_responsible_directories(responsible_dirs, desc_id,
hs_dirs_) < 0) {
log_warn(LD_REND, "Could not determine the responsible hidden service "
"directories to fetch descriptors.");
smartlist_free(responsible_dirs);
return;
}
replica = crypto_rand_int(REND_NUMBER_OF_CONSECUTIVE_REPLICAS);
hs_dir = smartlist_get(responsible_dirs, replica);
/* XXXX020 if hsdir fails, use another one... */
base32_encode(desc_id_base32, REND_DESC_ID_V2_BASE32 + 1,
desc_id, DIGEST_LEN);
/* Send fetch request. */
directory_initiate_command(hs_dir->address, hs_dir->addr,
hs_dir->or_port, hs_dir->dir_port, 0,
hs_dir->cache_info.identity_digest,
DIR_PURPOSE_FETCH_RENDDESC_V2,
ROUTER_PURPOSE_GENERAL,
1, desc_id_base32, NULL, 0, 0);
log_info(LD_REND, "Sending fetch request for v2 descriptor for "
"service '%s' with descriptor ID '%s' to hidden "
"service directory '%s' on port %d.",
query, desc_id_base32, hs_dir->nickname, hs_dir->dir_port);
smartlist_free(responsible_dirs);
}
......@@ -1526,6 +1526,21 @@ dirserv_thinks_router_is_unreliable(time_t now,
return 0;
}
/** Return true if <b>router</b> has an uptime of at least
* <b>__MinUptimeHidServDirectoryV2</b> and is reachable in the last
* REND_HS_DIR_REACHABLE_TIMEOUT seconds, else false.
*/
static int
dirserv_thinks_router_is_hs_dir(routerinfo_t *router, time_t now)
{
int uptime = real_uptime(router, now);
return (router->wants_to_be_hs_dir &&
uptime > get_options()->__MinUptimeHidServDirectoryV2 &&
((router_is_me(router) && !we_are_hibernating()) ||
(now < router->last_reachable + REND_HS_DIR_REACHABLE_TIMEOUT)));
}
/** Look through the routerlist, and assign the median uptime of running valid
* servers to stable_uptime, and the relative bandwidth capacities to
* fast_bandwidth and guard_bandwidth. Set total_bandwidth to the total
......@@ -1674,13 +1689,14 @@ routerstatus_format_entry(char *buf, size_t buf_len,
return 0;
cp = buf + strlen(buf);
r = tor_snprintf(cp, buf_len - (cp-buf),
"s%s%s%s%s%s%s%s%s%s%s%s\n",
"s%s%s%s%s%s%s%s%s%s%s%s%s\n",
/* These must stay in alphabetical order. */
rs->is_authority?" Authority":"",
rs->is_bad_exit?" BadExit":"",
rs->is_exit?" Exit":"",
rs->is_fast?" Fast":"",
rs->is_possible_guard?" Guard":"",
rs->is_hs_dir?" HSDir":"",
rs->is_named?" Named":"",
rs->is_running?" Running":"",
rs->is_stable?" Stable":"",
......@@ -1843,6 +1859,10 @@ set_routerstatus_from_routerinfo(routerstatus_t *rs,
rs->is_possible_guard = 0;
}
rs->is_bad_exit = listbadexits && ri->is_bad_exit;
ri->is_hs_dir = dirserv_thinks_router_is_hs_dir(ri, now);
if (get_options()->__ConsiderAllRoutersAsHidServDirectories)
ri->is_hs_dir = 1; /* Override real value. */
rs->is_hs_dir = ri->is_hs_dir;
/* 0.1.1.9-alpha is the first version to support fetch by descriptor
* hash. */
rs->is_v2_dir = ri->dir_port &&
......@@ -1992,7 +2012,7 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_env_t *private_key,
v3_out->server_versions = server_versions;
v3_out->known_flags = smartlist_create();
smartlist_split_string(v3_out->known_flags,
"Authority Exit Fast Guard Running Stable V2Dir Valid",
"Authority Exit Fast Guard HSDir Running Stable V2Dir Valid",
0, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
if (listbadexits)
smartlist_add(v3_out->known_flags, tor_strdup("BadExit"));
......
......@@ -1576,6 +1576,7 @@ routers_update_status_from_consensus_networkstatus(smartlist_t *routers,
router->is_possible_guard = rs->is_possible_guard;
router->is_exit = rs->is_exit;
router->is_bad_exit = rs->is_bad_exit;
router->is_hs_dir = rs->is_hs_dir;
}
if (router->is_running && ds) {
download_status_reset(&ds->v2_ns_dl_status);
......
......@@ -351,7 +351,13 @@ typedef enum {
/** Purpose for connection at a directory server. */
#define DIR_PURPOSE_SERVER 16
#define _DIR_PURPOSE_MAX 16
/** A connection to a hidden service directory server: upload a v2 rendezvous
* descriptor. */
#define DIR_PURPOSE_UPLOAD_RENDDESC_V2 17
/** A connection to a hidden service directory server: download a v2 rendezvous
* descriptor. */
#define DIR_PURPOSE_FETCH_RENDDESC_V2 18
#define _DIR_PURPOSE_MAX 18
#define _EXIT_PURPOSE_MIN 1
/** This exit stream wants to do an ordinary connect. */
......@@ -608,6 +614,14 @@ typedef enum {
/** Length of v2 descriptor ID (32 base32 chars = 160 bits). */
#define REND_DESC_ID_V2_BASE32 32
/** Length of the base32-encoded secret ID part of versioned hidden service
* descriptors. */
#define REND_SECRET_ID_PART_LEN_BASE32 32
/** Length of the base32-encoded hash of an introduction point's
* identity key. */
#define REND_INTRO_POINT_ID_LEN_BASE32 32
#define CELL_DIRECTION_IN 1
#define CELL_DIRECTION_OUT 2
......@@ -1197,6 +1211,11 @@ typedef struct {
unsigned int is_exit:1; /**< Do we think this is an OK exit? */
unsigned int is_bad_exit:1; /**< Do we think this exit is censored, borked,
* or otherwise nasty? */
unsigned int wants_to_be_hs_dir:1; /**< True iff this router has set a flag
to possibly act as hidden service
directory. */
unsigned int is_hs_dir:1; /**< True iff this router is a hidden service
* directory. */
/** Tor can use this router for general positions in circuits. */
#define ROUTER_PURPOSE_GENERAL 0
......@@ -1269,6 +1288,8 @@ typedef struct routerstatus_t {
* an exit node. */
unsigned int is_bad_directory:1; /**< Do we think this directory is junky,
* underpowered, or otherwise useless? */
unsigned int is_hs_dir:1; /** True iff this router is a hidden service
* directory. */
/** True iff we know version info for this router. (i.e., a "v" entry was
* included.) We'll replace all these with a big tor_version_t or a char[]
* if the number of traits we care about ever becomes incredibly big. */
......@@ -1998,6 +2019,10 @@ typedef struct {
int PublishHidServDescriptors;
int FetchServerDescriptors; /**< Do we fetch server descriptors as normal? */
int FetchHidServDescriptors; /** and hidden service descriptors? */
int HidServDirectoryV2; /**< Do we act as hs dir? */
int __MinUptimeHidServDirectoryV2; /**< Accept hs dirs after what time? */
int __ConsiderAllRoutersAsHidServDirectories; /**< Consider all routers as
* hidden service dirs? */
int FetchUselessDescriptors; /**< Do we fetch non-running descriptors too? */
int AllDirActionsPrivate; /**< Should every directory action be sent
* through a Tor circuit? */
......@@ -2849,6 +2874,12 @@ int dir_split_resource_into_fingerprints(const char *resource,
char *directory_dump_request_log(void);
int router_supports_extrainfo(const char *identity_digest, int is_authority);
void directory_post_to_hs_dir(smartlist_t *desc_ids, smartlist_t *descs,
const char *service_id, int seconds_valid,
smartlist_t *hs_dirs);
void directory_get_from_hs_dir(const char *desc_id, const char *query,
smartlist_t *hs_dirs);
time_t download_status_increment_failure(download_status_t *dls,
int status_code, const char *item,
int server, time_t now);
......@@ -3422,13 +3453,19 @@ typedef struct rend_cache_entry_t {
void rend_cache_init(void);
void rend_cache_clean(void);
void rend_cache_clean_up(void);
void rend_cache_clean_v2_dir(void);
void rend_cache_free_all(void);
int rend_valid_service_id(const char *query);
int rend_cache_lookup_desc(const char *query, int version, const char **desc,
size_t *desc_len);
int rend_cache_lookup_entry(const char *query, int version,
rend_cache_entry_t **entry_out);
int rend_cache_lookup_v2_dir(const char *query, char **desc);
int rend_cache_store(const char *desc, size_t desc_len, int published);
int rend_cache_store_v2_client(const char *desc,
const char *descriptor_cookie);
int rend_cache_store_v2_dir(const char *desc);
int rend_cache_size(void);
int rend_encode_v2_descriptors(smartlist_t *desc_strs_out,
smartlist_t *desc_ids_out,
......@@ -3702,6 +3739,18 @@ void routerlist_assert_ok(routerlist_t *rl);
const char *esc_router_info(routerinfo_t *router);
void routers_sort_by_identity(smartlist_t *routers);
smartlist_t *hid_serv_create_routing_table(void);
int hid_serv_have_enough_directories(smartlist_t *hs_dirs);
int hid_serv_get_responsible_directories(smartlist_t *responsible_dirs,
const char *id,
smartlist_t *hs_dirs);
routerinfo_t *hid_serv_next_directory(const char *id,
smartlist_t *hs_dirs);
routerinfo_t *hid_serv_previous_directory(const char *id,
smartlist_t *hs_dirs);
int hid_serv_acting_as_directory(smartlist_t *hs_dirs);
int hid_serv_responsible_for_desc_id(const char *id, smartlist_t *hs_dirs);
/********************************* routerparse.c ************************/
#define MAX_STATUS_TAG_LEN 32
......
......@@ -60,25 +60,13 @@ rend_service_descriptor_free(rend_service_descriptor_t *desc)
/*XXXX020 Rename to include "len" and maybe not "binary" */
#define REND_SERVICE_ID_BINARY 10
/** Length of the time period that is used to encode the secret ID part of
* versioned hidden service descriptors. */
/*XXXX020 Rename to include "len" and maybe not "binary" */
#define REND_TIME_PERIOD_BINARY 4
/** Length of the descriptor cookie that is used for versioned hidden
* service descriptors. */
/* XXXX020 rename to REND_DESC_COOKIE_(BINARY_)LEN */
#define REND_DESC_COOKIE_BINARY 16
#define REND_DESC_COOKIE_LEN 16
/** Length of the replica number that is used to determine the secret ID
* part of versioned hidden service descriptors. */
/* XXXX020 rename to REND_REPLICA_(BINARY_)LEN */
#define REND_REPLICA_BINARY 1
/** Length of the base32-encoded secret ID part of versioned hidden service
* descriptors. */
/*XXXX020 Rename to include "len" */
#define REND_SECRET_ID_PART_BASE32 32
#define REND_REPLICA_LEN 1
/** Compute the descriptor ID for <b>service_id</b> of length
* <b>REND_SERVICE_ID_BINARY</b> and <b>secret_id_part</b> of length
......@@ -98,7 +86,7 @@ rend_get_descriptor_id_bytes(char *descriptor_id_out,
/** Compute the secret ID part for time_period,
* a <b>descriptor_cookie</b> of length
* <b>REND_DESC_COOKIE_BINARY</b> which may also be <b>NULL</b> if no
* <b>REND_DESC_COOKIE_LEN</b> which may also be <b>NULL</b> if no
* descriptor_cookie shall be used, and <b>replica</b>, and write it to
* <b>secret_id_part</b> of length DIGEST_LEN. */
static void
......@@ -110,9 +98,9 @@ get_secret_id_part_bytes(char *secret_id_part, uint32_t time_period,
crypto_digest_add_bytes(digest, (char*)&time_period, sizeof(uint32_t));
if (descriptor_cookie) {
crypto_digest_add_bytes(digest, descriptor_cookie,
REND_DESC_COOKIE_BINARY);
REND_DESC_COOKIE_LEN);
}
crypto_digest_add_bytes(digest, (const char *)&replica, REND_REPLICA_BINARY);
crypto_digest_add_bytes(digest, (const char *)&replica, REND_REPLICA_LEN);
crypto_digest_get_digest(digest, secret_id_part, DIGEST_LEN);
crypto_free_digest_env(digest);
}
......@@ -146,7 +134,7 @@ get_seconds_valid(time_t now, const char *service_id)
/** Compute the binary <b>desc_id_out</b> (DIGEST_LEN bytes long) for a given
* base32-encoded <b>service_id</b> and optional unencoded
* <b>descriptor_cookie</b> of length REND_DESC_COOKIE_BINARY,
* <b>descriptor_cookie</b> of length REND_DESC_COOKIE_LEN,
* at time <b>now</b> for replica number
* <b>replica</b>. <b>desc_id</b> needs to have <b>DIGEST_LEN</b> bytes
* free. Return 0 for success, -1 otherwise. */
......@@ -188,7 +176,7 @@ rend_compute_v2_desc_id(char *desc_id_out, const char *service_id,
}
/* Encode the introduction points in <b>desc</b>, optionally encrypt them with
* an optional <b>descriptor_cookie</b> of length REND_DESC_COOKIE_BINARY,
* an optional <b>descriptor_cookie</b> of length REND_DESC_COOKIE_LEN,
* encode it in base64, and write it to a newly allocated string, and write a
* pointer to it to *<b>ipos_base64</b>. Return 0 for success, -1
* otherwise. */
......@@ -207,7 +195,7 @@ rend_encode_v2_intro_points(char **ipos_base64,
unenc_len = desc->n_intro_points * 1000; /* too long, but ok. */
unenc = tor_malloc_zero(unenc_len);
for (i = 0; i < desc->n_intro_points; i++) {
char id_base32[32 + 1]; /*XXXX020 should be a macro */
char id_base32[REND_INTRO_POINT_ID_LEN_BASE32 + 1];
char *onion_key = NULL;
size_t onion_key_len;
crypto_pk_env_t *intro_key;
......@@ -370,7 +358,7 @@ rend_encode_v2_descriptors(smartlist_t *desc_strs_out,
/* Encode REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS descriptors. */
for (k = 0; k < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS; k++) {
char secret_id_part[DIGEST_LEN];
char secret_id_part_base32[REND_SECRET_ID_PART_BASE32 + 1];
char secret_id_part_base32[REND_SECRET_ID_PART_LEN_BASE32 + 1];
char *desc_id;
char desc_id_base32[REND_DESC_ID_V2_BASE32 + 1];
char *permanent_key = NULL;
......@@ -387,7 +375,7 @@ rend_encode_v2_descriptors(smartlist_t *desc_strs_out,
/* Calculate secret-id-part = h(time-period + cookie + replica). */
get_secret_id_part_bytes(secret_id_part, time_period, descriptor_cookie,
k);
base32_encode(secret_id_part_base32, REND_SECRET_ID_PART_BASE32 + 1,
base32_encode(secret_id_part_base32, REND_SECRET_ID_PART_LEN_BASE32 + 1,
secret_id_part, DIGEST_LEN);
/* Calculate descriptor ID. */
desc_id = tor_malloc_zero(DIGEST_LEN);
......@@ -628,12 +616,17 @@ rend_get_service_id(crypto_pk_env_t *pk, char *out)
* rend_cache_entry_t. */
static strmap_t *rend_cache = NULL;
/** Map from descriptor id to rend_cache_entry_t; only for hidden service
* directories. */
static digestmap_t *rend_cache_v2_dir = NULL;
/** Initializes the service descriptor cache.
*/
void
rend_cache_init(void)
{
rend_cache = strmap_new();
rend_cache_v2_dir = digestmap_new();
}
/** Helper: free storage held by a single service descriptor cache entry. */
......@@ -651,7 +644,9 @@ void
rend_cache_free_all(void)
{
strmap_free(rend_cache, _rend_cache_entry_free);
digestmap_free(rend_cache_v2_dir, _rend_cache_entry_free);
rend_cache = NULL;
rend_cache_v2_dir = NULL;
}
/** Removes all old entries from the service descriptor cache.
......@@ -677,6 +672,88 @@ rend_cache_clean(void)
}
}
/** Remove all old entries on v2 hidden service directories. */
void
rend_cache_clean_v2_dir(void)
{
digestmap_iter_t *iter;
const char *key;
void *val;
rend_cache_entry_t *ent;
time_t cutoff;