⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dirvote.c

📁 关于tor匿名通信的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
                    tor_strdup(hex_str(ds->v3_identity_digest, DIGEST_LEN))));
  keys = smartlist_join_strings(known_v3_keys, ", ", 0, NULL);
  SMARTLIST_FOREACH(known_v3_keys, char *, cp, tor_free(cp));
  smartlist_free(known_v3_keys);
  return keys;
}

/** Called when we have received a networkstatus vote in <b>vote_body</b>.
 * Parse and validate it, and on success store it as a pending vote (which we
 * then return).  Return NULL on failure.  Sets *<b>msg_out</b> and
 * *<b>status_out</b> to an HTTP response and status code.  (V3 authority
 * only) */
pending_vote_t *
dirvote_add_vote(const char *vote_body, const char **msg_out, int *status_out)
{
  networkstatus_t *vote;
  networkstatus_voter_info_t *vi;
  trusted_dir_server_t *ds;
  pending_vote_t *pending_vote = NULL;
  const char *end_of_vote = NULL;
  int any_failed = 0;
  tor_assert(vote_body);
  tor_assert(msg_out);
  tor_assert(status_out);

  if (!pending_vote_list)
    pending_vote_list = smartlist_create();
  *status_out = 0;
  *msg_out = NULL;

 again:
  vote = networkstatus_parse_vote_from_string(vote_body, &end_of_vote, 1);
  if (!end_of_vote)
    end_of_vote = vote_body + strlen(vote_body);
  if (!vote) {
    log_warn(LD_DIR, "Couldn't parse vote: length was %d",
             (int)strlen(vote_body));
    *msg_out = "Unable to parse vote";
    goto err;
  }
  tor_assert(smartlist_len(vote->voters) == 1);
  vi = get_voter(vote);
  tor_assert(vi->good_signature == 1);
  ds = trusteddirserver_get_by_v3_auth_digest(vi->identity_digest);
  if (!ds) {
    char *keys = list_v3_auth_ids();
    log_warn(LD_DIR, "Got a vote from an authority (nickname %s, address %s) "
             "with authority key ID %s. "
             "This key ID is not recognized.  Known v3 key IDs are: %s",
             vi->nickname, vi->address,
             hex_str(vi->identity_digest, DIGEST_LEN), keys);
    tor_free(keys);
    *msg_out = "Vote not from a recognized v3 authority";
    goto err;
  }
  tor_assert(vote->cert);
  if (!authority_cert_get_by_digests(vote->cert->cache_info.identity_digest,
                                     vote->cert->signing_key_digest)) {
    /* Hey, it's a new cert! */
    trusted_dirs_load_certs_from_string(
                               vote->cert->cache_info.signed_descriptor_body,
                               0 /* from_store */, 1 /*flush*/);
    if (!authority_cert_get_by_digests(vote->cert->cache_info.identity_digest,
                                       vote->cert->signing_key_digest)) {
      log_warn(LD_BUG, "We added a cert, but still couldn't find it.");
    }
  }

  /* Is it for the right period? */
  if (vote->valid_after != voting_schedule.interval_starts) {
    char tbuf1[ISO_TIME_LEN+1], tbuf2[ISO_TIME_LEN+1];
    format_iso_time(tbuf1, vote->valid_after);
    format_iso_time(tbuf2, voting_schedule.interval_starts);
    log_warn(LD_DIR, "Rejecting vote from %s with valid-after time of %s; "
             "we were expecting %s", vi->address, tbuf1, tbuf2);
    *msg_out = "Bad valid-after time";
    goto err;
  }

  /* Now see whether we already h<ave a vote from this authority.*/
  SMARTLIST_FOREACH(pending_vote_list, pending_vote_t *, v, {
      if (! memcmp(v->vote->cert->cache_info.identity_digest,
                   vote->cert->cache_info.identity_digest,
                   DIGEST_LEN)) {
        networkstatus_voter_info_t *vi_old = get_voter(v->vote);
        if (!memcmp(vi_old->vote_digest, vi->vote_digest, DIGEST_LEN)) {
          /* Ah, it's the same vote. Not a problem. */
          log_info(LD_DIR, "Discarding a vote we already have.");
          if (*status_out < 200)
            *status_out = 200;
          goto discard;
        } else if (v->vote->published < vote->published) {
          log_notice(LD_DIR, "Replacing an older pending vote from this "
                     "directory.");
          cached_dir_decref(v->vote_body);
          networkstatus_vote_free(v->vote);
          v->vote_body = new_cached_dir(tor_strndup(vote_body,
                                                    end_of_vote-vote_body),
                                        vote->published);
          v->vote = vote;
          if (end_of_vote &&
              !strcmpstart(end_of_vote, "network-status-version"))
            goto again;

          if (*status_out < 200)
            *status_out = 200;
          if (!*msg_out)
            *msg_out = "OK";
          return v;
        } else {
          *msg_out = "Already have a newer pending vote";
          goto err;
        }
      }
    });

  pending_vote = tor_malloc_zero(sizeof(pending_vote_t));
  pending_vote->vote_body = new_cached_dir(tor_strndup(vote_body,
                                                       end_of_vote-vote_body),
                                           vote->published);
  pending_vote->vote = vote;
  smartlist_add(pending_vote_list, pending_vote);

  if (!strcmpstart(end_of_vote, "network-status-version ")) {
    vote_body = end_of_vote;
    goto again;
  }

  goto done;

 err:
  any_failed = 1;
  if (!*msg_out)
    *msg_out = "Error adding vote";
  if (*status_out < 400)
    *status_out = 400;

 discard:
  if (vote)
    networkstatus_vote_free(vote);

  if (end_of_vote && !strcmpstart(end_of_vote, "network-status-version ")) {
    vote_body = end_of_vote;
    goto again;
  }

 done:

  if (*status_out < 200)
    *status_out = 200;
  if (!*msg_out) {
    if (!any_failed && !pending_vote) {
      *msg_out = "Duplicate discarded";
    } else {
      *msg_out = "ok";
    }
  }

  return any_failed ? NULL : pending_vote;
}

/** Try to compute a v3 networkstatus consensus from the currently pending
 * votes.  Return 0 on success, -1 on failure.  Store the consensus in
 * pending_consensus: it won't be ready to be published until we have
 * everybody else's signatures collected too. (V3 Authoritity only) */
static int
dirvote_compute_consensus(void)
{
  /* Have we got enough votes to try? */
  int n_votes, n_voters;
  smartlist_t *votes = NULL;
  char *consensus_body = NULL, *signatures = NULL;
  networkstatus_t *consensus = NULL;
  authority_cert_t *my_cert;

  if (!pending_vote_list)
    pending_vote_list = smartlist_create();

  n_voters = get_n_authorities(V3_AUTHORITY);
  n_votes = smartlist_len(pending_vote_list);
  if (n_votes <= n_voters/2) {
    log_warn(LD_DIR, "We don't have enough votes to generate a consensus: "
             "%d of %d", n_votes, n_voters/2);
    goto err;
  }

  if (!(my_cert = get_my_v3_authority_cert())) {
    log_warn(LD_DIR, "Can't generate consensus without a certificate.");
    goto err;
  }

  votes = smartlist_create();
  SMARTLIST_FOREACH(pending_vote_list, pending_vote_t *, v,
                    smartlist_add(votes, v->vote));

  consensus_body = networkstatus_compute_consensus(
        votes, n_voters,
        my_cert->identity_key,
        get_my_v3_authority_signing_key());
  if (!consensus_body) {
    log_warn(LD_DIR, "Couldn't generate a consensus at all!");
    goto err;
  }
  consensus = networkstatus_parse_vote_from_string(consensus_body, NULL, 0);
  if (!consensus) {
    log_warn(LD_DIR, "Couldn't parse consensus we generated!");
    goto err;
  }
  /* 'Check' our own signature, to mark it valid. */
  networkstatus_check_consensus_signature(consensus, -1);

  signatures = networkstatus_get_detached_signatures(consensus);
  if (!signatures) {
    log_warn(LD_DIR, "Couldn't extract signatures.");
    goto err;
  }

  tor_free(pending_consensus_body);
  pending_consensus_body = consensus_body;
  tor_free(pending_consensus_signatures);
  pending_consensus_signatures = signatures;

  if (pending_consensus)
    networkstatus_vote_free(pending_consensus);
  pending_consensus = consensus;

  if (pending_consensus_signature_list) {
    int n_sigs = 0;
    /* we may have gotten signatures for this consensus before we built
     * it ourself.  Add them now. */
    SMARTLIST_FOREACH(pending_consensus_signature_list, char *, sig,
      {
        const char *msg = NULL;
        int r = dirvote_add_signatures_to_pending_consensus(sig, &msg);
        if (r >= 0)
          n_sigs += r;
        else
          log_warn(LD_DIR,
                   "Could not add queued signature to new consensus: %s",
                   msg);
        tor_free(sig);
      });
    if (n_sigs)
      log_notice(LD_DIR, "Added %d pending signatures while building "
                 "consensus.", n_sigs);
    smartlist_clear(pending_consensus_signature_list);
  }

  log_notice(LD_DIR, "Consensus computed; uploading signature(s)");

  directory_post_to_dirservers(DIR_PURPOSE_UPLOAD_SIGNATURES,
                               ROUTER_PURPOSE_GENERAL,
                               V3_AUTHORITY,
                               pending_consensus_signatures,
                               strlen(pending_consensus_signatures), 0);
  log_notice(LD_DIR, "Signature(s) posted.");

  return 0;
 err:
  if (votes)
    smartlist_free(votes);
  tor_free(consensus_body);
  tor_free(signatures);
  networkstatus_vote_free(consensus);

  return -1;
}

/** Helper: we just got the <b>detached_signatures_body</b> sent to us as
 * signatures on the currently pending consensus.  Add them to the consensus
 * as appropriate.  Return the number of signatures added. (?) */
static int
dirvote_add_signatures_to_pending_consensus(
                       const char *detached_signatures_body,
                       const char **msg_out)
{
  ns_detached_signatures_t *sigs = NULL;
  int r = -1;

  tor_assert(detached_signatures_body);
  tor_assert(msg_out);

  /* Only call if we have a pending consensus right now. */
  tor_assert(pending_consensus);
  tor_assert(pending_consensus_body);
  tor_assert(pending_consensus_signatures);

  *msg_out = NULL;

  if (!(sigs = networkstatus_parse_detached_signatures(
                               detached_signatures_body, NULL))) {
    *msg_out = "Couldn't parse detached signatures.";
    goto err;
  }

  log_info(LD_DIR, "Have %d signatures for adding to consensus.",
                   smartlist_len(sigs->signatures));
  r = networkstatus_add_detached_signatures(pending_consensus,
                                            sigs, msg_out);
  log_info(LD_DIR,"Added %d signatures to consensus.", r);

  if (r >= 0) {
    char *new_detached =
      networkstatus_get_detached_signatures(pending_consensus);
    const char *src;
    char *dst, *dst_end;
    size_t new_consensus_len =
      strlen(pending_consensus_body) + strlen(new_detached) + 1;
    pending_consensus_body = tor_realloc(pending_consensus_body,
                                         new_consensus_len);
    dst_end = pending_consensus_body + new_consensus_len;
    dst = strstr(pending_consensus_body, "directory-signature ");
    tor_assert(dst);
    src = strstr(new_detached, "directory-signature ");
    tor_assert(src);
    strlcpy(dst, src, dst_end-dst);

    /* We remove this block once it has failed to crash for a while.  But
     * unless it shows up in profiles, we're probably better leaving it in,
     * just in case we break detached signature processing at some point. */
    {
      ns_detached_signatures_t *sigs =
        networkstatus_parse_detached_signatures(new_detached, NULL);
      networkstatus_t *v = networkstatus_parse_vote_from_string(
                                             pending_consensus_body, NULL, 0);
      tor_assert(sigs);
      ns_detached_signatures_free(sigs);
      tor_assert(v);
      networkstatus_vote_free(v);
    }
    tor_free(pending_consensus_signatures);
    pending_consensus_signatures = new_detached;
    *msg_out = "Signatures added";
  } else {
    goto err;
  }

  goto done;
 err:
  if (!msg_out)
    *msg_out = "Unrecognized error while adding detached signatures.";
 done:
  if (sigs)
    ns_detached_signatures_free(sigs);
  return r;
}

/** Helper: we just got the <b>deteached_signatures_body</b> sent to us as
 * signatures on the currently pending consensus.  Add them to the pending
 * consensus (if we have one); otherwise queue them until we have a
 * consensus.  Return negative on failure, nonnegative on success. */
int
dirvote_add_signatures(const char *detached_signatures_body,
                       const char *source,
                       const char **msg)
{
  if (pending_consensus) {
    log_notice(LD_DIR, "Got a signature from %s. "
                       "Adding it to the pending consensus.", source);
    return dirvote_add_signatures_to_pending_consensus(
                                     detached_signatures_body, msg);
  } else {
    log_notice(LD_DIR, "Got a signature from %s. "
                       "Queueing it for the next consensus.", source);
    if (!pending_consensus_signature_list)
      pending_consensus_signature_list = smartlist_create();
    smartlist_add(pending_consensus_signature_list,
                  tor_strdup(d

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -