Commit 7fc64f02 authored by George Kadianakis's avatar George Kadianakis Committed by Nick Mathewson
Browse files

Introduce cache for outdated microdesc dirservers.

We gonna use this cache to avoid dirservers without outdated md info.
parent 1d5e693b
Loading
Loading
Loading
Loading
+23 −13
Original line number Diff line number Diff line
@@ -117,7 +117,8 @@ static void dir_routerdesc_download_failed(smartlist_t *failed,
                                           int was_extrainfo,
                                           int was_descriptor_digests);
static void dir_microdesc_download_failed(smartlist_t *failed,
                                          int status_code);
                                          int status_code,
                                          const char *dir_id);
static int client_likes_consensus(const struct consensus_cache_entry_t *ent,
                                  const char *want_url);

@@ -2178,8 +2179,6 @@ static int handle_response_fetch_detached_signatures(dir_connection_t *,
                                             const response_handler_args_t *);
static int handle_response_fetch_desc(dir_connection_t *,
                                             const response_handler_args_t *);
static int handle_response_fetch_microdesc(dir_connection_t *,
                                           const response_handler_args_t *);
static int handle_response_upload_dir(dir_connection_t *,
                                      const response_handler_args_t *);
static int handle_response_upload_vote(dir_connection_t *,
@@ -2839,7 +2838,7 @@ handle_response_fetch_desc(dir_connection_t *conn,
 * Handler function: processes a response to a request for a group of
 * microdescriptors
 **/
static int
STATIC int
handle_response_fetch_microdesc(dir_connection_t *conn,
                                const response_handler_args_t *args)
{
@@ -2856,6 +2855,7 @@ handle_response_fetch_microdesc(dir_connection_t *conn,
           conn->base_.port);
  tor_assert(conn->requested_resource &&
             !strcmpstart(conn->requested_resource, "d/"));
  tor_assert_nonfatal(!tor_mem_is_zero(conn->identity_digest, DIGEST_LEN));
  which = smartlist_new();
  dir_split_resource_into_fingerprints(conn->requested_resource+2,
                                       which, NULL,
@@ -2866,7 +2866,7 @@ handle_response_fetch_microdesc(dir_connection_t *conn,
             "soon.",
             status_code, escaped(reason), conn->base_.address,
             (int)conn->base_.port, conn->requested_resource);
    dir_microdesc_download_failed(which, status_code);
    dir_microdesc_download_failed(which, status_code, conn->identity_digest);
    SMARTLIST_FOREACH(which, char *, cp, tor_free(cp));
    smartlist_free(which);
    return 0;
@@ -2878,7 +2878,7 @@ handle_response_fetch_microdesc(dir_connection_t *conn,
                                  now, which);
    if (smartlist_len(which)) {
      /* Mark remaining ones as failed. */
      dir_microdesc_download_failed(which, status_code);
      dir_microdesc_download_failed(which, status_code, conn->identity_digest);
    }
    if (mds && smartlist_len(mds)) {
      control_event_bootstrap(BOOTSTRAP_STATUS_LOADING_DESCRIPTORS,
@@ -5546,13 +5546,14 @@ dir_routerdesc_download_failed(smartlist_t *failed, int status_code,
   * every 10 or 60 seconds (FOO_DESCRIPTOR_RETRY_INTERVAL) in main.c. */
}

/** Called when a connection to download microdescriptors has failed in whole
 * or in part. <b>failed</b> is a list of every microdesc digest we didn't
 * get. <b>status_code</b> is the http status code we received. Reschedule the
 * microdesc downloads as appropriate. */
/** Called when a connection to download microdescriptors from relay with
 * <b>dir_id</b> has failed in whole or in part. <b>failed</b> is a list
 * of every microdesc digest we didn't get. <b>status_code</b> is the http
 * status code we received. Reschedule the microdesc downloads as
 * appropriate. */
static void
dir_microdesc_download_failed(smartlist_t *failed,
                              int status_code)
                              int status_code, const char *dir_id)
{
  networkstatus_t *consensus
    = networkstatus_get_latest_consensus_by_flavor(FLAV_MICRODESC);
@@ -5563,17 +5564,26 @@ dir_microdesc_download_failed(smartlist_t *failed,

  if (! consensus)
    return;

  /* We failed to fetch a microdescriptor from 'dir_id', note it down
   * so that we don't try the same relay next time... */
  microdesc_note_outdated_dirserver(dir_id);

  SMARTLIST_FOREACH_BEGIN(failed, const char *, d) {
    rs = router_get_mutable_consensus_status_by_descriptor_digest(consensus,d);
    if (!rs)
      continue;
    dls = &rs->dl_status;
    if (dls->n_download_failures >=
        get_options()->TestingMicrodescMaxDownloadTries)
        get_options()->TestingMicrodescMaxDownloadTries) {
      continue;
    {
    }

    { /* Increment the failure count for this md fetch */
      char buf[BASE64_DIGEST256_LEN+1];
      digest256_to_base64(buf, d);
      log_info(LD_DIR, "Failed to download md %s from %s",
               buf, hex_str(dir_id, DIGEST_LEN));
      download_status_increment_failure(dls, status_code, buf,
                                        server, now);
    }
+6 −1
Original line number Diff line number Diff line
@@ -166,7 +166,12 @@ STATIC char *accept_encoding_header(void);
STATIC int allowed_anonymous_connection_compression_method(compress_method_t);
STATIC void warn_disallowed_anonymous_compression_method(compress_method_t);

#endif
struct response_handler_args_t;

STATIC int handle_response_fetch_microdesc(dir_connection_t *conn,
                                 const struct response_handler_args_t *args);

#endif /* defined(DIRECTORY_PRIVATE) */

#ifdef TOR_UNIT_TESTS
/* Used only by test_dir.c */
+101 −0
Original line number Diff line number Diff line
@@ -74,6 +74,102 @@ HT_GENERATE2(microdesc_map, microdesc_t, node,
             microdesc_hash_, microdesc_eq_, 0.6,
             tor_reallocarray_, tor_free_)

/************************* md fetch fail cache *****************************/

/* If we end up with too many outdated dirservers, something probably went
 * wrong so clean up the list. */
#define TOO_MANY_OUTDATED_DIRSERVERS 30

/** List of dirservers with outdated microdesc information. The smartlist is
 *  filled with the hex digests of outdated dirservers. */
static smartlist_t *outdated_dirserver_list = NULL;

/** Note that we failed to fetch a microdescriptor from the relay with
 *  <b>relay_digest</b> (of size DIGEST_LEN). */
void
microdesc_note_outdated_dirserver(const char *relay_digest)
{
  char relay_hexdigest[HEX_DIGEST_LEN+1];

  /* Don't register outdated dirservers if we don't have a live consensus,
   * since we might be trying to fetch microdescriptors that are not even
   * currently active. */
  if (!networkstatus_get_live_consensus(approx_time())) {
    return;
  }

  if (!outdated_dirserver_list) {
    outdated_dirserver_list = smartlist_new();
  }

  tor_assert(outdated_dirserver_list);

  /* If the list grows too big, clean it up */
  if (BUG(smartlist_len(outdated_dirserver_list) >
          TOO_MANY_OUTDATED_DIRSERVERS)) {
    microdesc_reset_outdated_dirservers_list();
  }

  /* Turn the binary relay digest to a hex since smartlists have better support
   * for strings than digests. */
  base16_encode(relay_hexdigest,sizeof(relay_hexdigest),
                relay_digest, DIGEST_LEN);

  /* Make sure we don't add a dirauth as an outdated dirserver */
  if (router_get_trusteddirserver_by_digest(relay_digest)) {
    log_info(LD_GENERAL, "Auth %s gave us outdated dirinfo.", relay_hexdigest);
    return;
  }

  /* Don't double-add outdated dirservers */
  if (smartlist_contains_string(outdated_dirserver_list, relay_hexdigest)) {
    return;
  }

  /* Add it to the list of outdated dirservers */
  smartlist_add_strdup(outdated_dirserver_list, relay_hexdigest);

  log_info(LD_GENERAL, "Noted %s as outdated md dirserver", relay_hexdigest);
}

/** Return True if the relay with <b>relay_digest</b> (size DIGEST_LEN) is an
 *  outdated dirserver */
int
microdesc_relay_is_outdated_dirserver(const char *relay_digest)
{
  char relay_hexdigest[HEX_DIGEST_LEN+1];

  if (!outdated_dirserver_list) {
    return 0;
  }

  /* Convert identity digest to hex digest */
  base16_encode(relay_hexdigest, sizeof(relay_hexdigest),
                relay_digest, DIGEST_LEN);

  /* Last time we tried to fetch microdescs, was this directory mirror missing
   * any mds we asked for? */
  if (smartlist_contains_string(outdated_dirserver_list, relay_hexdigest)) {
    return 1;
  }

  return 0;
}

/** Reset the list of outdated dirservers. */
void
microdesc_reset_outdated_dirservers_list(void)
{
  if (!outdated_dirserver_list) {
    return;
  }

  SMARTLIST_FOREACH(outdated_dirserver_list, char *, cp, tor_free(cp));
  smartlist_clear(outdated_dirserver_list);
}

/****************************************************************************/

/** Write the body of <b>md</b> into <b>f</b>, with appropriate annotations.
 * On success, return the total number of bytes written, and set
 * *<b>annotation_len_out</b> to the number of bytes written as
@@ -789,6 +885,11 @@ microdesc_free_all(void)
    tor_free(the_microdesc_cache->journal_fname);
    tor_free(the_microdesc_cache);
  }

  if (outdated_dirserver_list) {
    SMARTLIST_FOREACH(outdated_dirserver_list, char *, cp, tor_free(cp));
    smartlist_free(outdated_dirserver_list);
  }
}

/** If there is a microdescriptor in <b>cache</b> whose sha256 digest is
+5 −1
Original line number Diff line number Diff line
@@ -50,5 +50,9 @@ int we_fetch_microdescriptors(const or_options_t *options);
int we_fetch_router_descriptors(const or_options_t *options);
int we_use_microdescriptors_for_circuits(const or_options_t *options);

#endif
void microdesc_note_outdated_dirserver(const char *relay_digest);
int microdesc_relay_is_outdated_dirserver(const char *relay_digest);
void microdesc_reset_outdated_dirservers_list(void);

#endif /* !defined(TOR_MICRODESC_H) */
+3 −0
Original line number Diff line number Diff line
@@ -2041,6 +2041,9 @@ networkstatus_set_current_consensus(const char *consensus,
                    "CLOCK_SKEW MIN_SKEW=%ld SOURCE=CONSENSUS", delta);
  }

  /* We got a new consesus. Reset our md fetch fail cache */
  microdesc_reset_outdated_dirservers_list();

  router_dir_info_changed();

  result = 0;