Commit a66f2593 authored by Nick Mathewson's avatar Nick Mathewson 🤹
Browse files

r13902@catbus: nickm | 2007-07-25 17:43:52 -0400

 Some dirvote code to handle generating votes and slinging them around.  More code is still needed.


svn:r10927
parent 1b7a704c
Loading
Loading
Loading
Loading
+46 −0
Original line number Diff line number Diff line
@@ -78,6 +78,7 @@ purpose_needs_anonymity(uint8_t dir_purpose, uint8_t router_purpose)
    return 1; /* if we have to ask, better make it anonymous */
  if (dir_purpose == DIR_PURPOSE_FETCH_DIR ||
      dir_purpose == DIR_PURPOSE_UPLOAD_DIR ||
      dir_purpose == DIR_PURPOSE_UPLOAD_VOTE ||
      dir_purpose == DIR_PURPOSE_FETCH_RUNNING_LIST ||
      dir_purpose == DIR_PURPOSE_FETCH_NETWORKSTATUS ||
      dir_purpose == DIR_PURPOSE_FETCH_SERVERDESC ||
@@ -501,6 +502,9 @@ directory_initiate_command(const char *address, uint32_t addr,
    case DIR_PURPOSE_UPLOAD_RENDDESC:
      log_debug(LD_REND,"initiating hidden-service descriptor upload");
      break;
    case DIR_PURPOSE_UPLOAD_VOTE:
      log_debug(LD_OR,"initiating server vote upload");
      break;
    case DIR_PURPOSE_FETCH_RUNNING_LIST:
      log_debug(LD_DIR,"initiating running-routers fetch");
      break;
@@ -685,6 +689,12 @@ directory_send_command(dir_connection_t *conn,
      httpcommand = "POST";
      url = tor_strdup("/tor/");
      break;
    case DIR_PURPOSE_UPLOAD_VOTE:
      tor_assert(!resource);
      tor_assert(payload);
      httpcommand = "POST";
      url = tor_strdup("/tor/post/vote");
      break;
    case DIR_PURPOSE_FETCH_RENDDESC:
      tor_assert(resource);
      tor_assert(!payload);
@@ -1367,6 +1377,30 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
     * dirservers down just because they don't like us. */
  }

  if (conn->_base.purpose == DIR_PURPOSE_UPLOAD_VOTE) {
    switch (status_code) {
      case 200: {
        log_notice(LD_DIR,"Uploaded a vote to dirserver %s:%d",
                   conn->_base.address, conn->_base.port);
        }
        break;
      case 400:
        log_warn(LD_GENERAL,"http status 400 (%s) response after uploading "
                 "vote to dirserver '%s:%d'. Please correct.",
                 escaped(reason), conn->_base.address, conn->_base.port);
        break;
      default:
        log_warn(LD_GENERAL,
             "http status %d (%s) reason unexpected while uploading "
             "vote to server '%s:%d').",
             status_code, escaped(reason), conn->_base.address,
             conn->_base.port);
        break;
    }
    /* return 0 in all cases, since we don't want to mark any
     * dirservers down just because they don't like us. */
  }

  if (conn->_base.purpose == DIR_PURPOSE_FETCH_RENDDESC) {
    log_info(LD_REND,"Received rendezvous descriptor (size %d, status %d "
             "(%s))",
@@ -2075,6 +2109,18 @@ directory_handle_command_post(dir_connection_t *conn, const char *headers,
    goto done;
  }

  if (authdir_mode_v3(options) &&
      !strcmp(url,"/tor/post/vote")) { /* server descriptor post */
    const char *msg = "OK";
    if (dirserv_add_vote(body, &msg)) {
      write_http_status_line(conn, 200, "Vote stored");
    } else {
      tor_assert(msg);
      write_http_status_line(conn, 400, msg);
    }
    goto done;
  }

  /* we didn't recognize the url */
  write_http_status_line(conn, 404, "Not found");

+4 −2
Original line number Diff line number Diff line
@@ -1116,7 +1116,7 @@ cached_dir_decref(cached_dir_t *d)

/** Allocate and return a new cached_dir_t containing the string <b>s</b>,
 * published at <b>published</b>. */
static cached_dir_t *
cached_dir_t *
new_cached_dir(char *s, time_t published)
{
  cached_dir_t *d = tor_malloc_zero(sizeof(cached_dir_t));
@@ -2075,7 +2075,9 @@ format_networkstatus_vote(crypto_pk_env_t *private_signing_key,
  return status;
}

static cached_dir_t *
/** DOCDOC */
/* XXXX020 possibly rename and relocate to dirvote.c? */
cached_dir_t *
generate_v3_networkstatus(void)
{
  crypto_pk_env_t *key = get_my_v3_authority_signing_key();
+154 −0
Original line number Diff line number Diff line
@@ -866,3 +866,157 @@ dirvote_recalculate_timing(time_t now)
  voting_schedule.voting_starts = start - vote_delay - dist_delay;
}

/** DOCDOC */
typedef struct pending_vote_t {
  cached_dir_t *vote_body;
  networkstatus_vote_t *vote;
} pending_vote_t;

/** DOCDOC */
static smartlist_t *pending_vote_list = NULL;
/** DOCDOC */
static char *pending_consensus_body = NULL;

/** DOCDOC */
void
dirvote_perform_vote(void)
{
  cached_dir_t *new_vote = generate_v3_networkstatus();
  pending_vote_t *pending_vote;
  const char *msg = "";

  if ((pending_vote = dirvote_add_vote(tor_memdup(new_vote->dir,
                                                  new_vote->dir_len), &msg))) {
    log_warn(LD_DIR, "Couldn't store my own vote! (I told myself, '%s'.)",
             msg);
    return;
  }

  directory_post_to_dirservers(DIR_PURPOSE_UPLOAD_VOTE,
                               ROUTER_PURPOSE_GENERAL,
                               V3_AUTHORITY,
                               pending_vote->vote_body->dir,
                               pending_vote->vote_body->dir_len, 0);
}

/** DOCDOC */
void
dirvote_clear_pending_votes(void)
{
  if (!pending_vote_list)
    return;
  SMARTLIST_FOREACH(pending_vote_list, pending_vote_t *, v, {
      cached_dir_decref(v->vote_body);
      v->vote_body = NULL;
      networkstatus_vote_free(v->vote);
      tor_free(v);
    });
  smartlist_clear(pending_vote_list);
}

/** DOCDOC */
pending_vote_t *
dirvote_add_vote(char *vote_body, const char **msg_out)
{
  networkstatus_vote_t *vote;
  networkstatus_voter_info_t *vi;
  trusted_dir_server_t *ds;
  pending_vote_t *pending_vote = NULL;
  tor_assert(vote_body);
  tor_assert(msg_out);

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

  vote = networkstatus_parse_vote_from_string(vote_body, 1);
  if (!vote) {
    *msg_out = "Unable to parse vote";
    goto err;
  }
  tor_assert(smartlist_len(vote->voters) == 1);
  vi = smartlist_get(vote->voters, 0);
  tor_assert(vi->good_signature == 1);
  ds = trusteddirserver_get_by_v3_auth_digest(vi->identity_digest);
  if (!ds || !(ds->type & V3_AUTHORITY)) {
    *msg_out = "Vote not from a recognized v3 authority";
    goto err;
  }
  /* XXXX020 check times; make sure epochs match. */

  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)) {
        log_notice(LD_DIR, "We already have a pending vote from this dir");
        if (v->vote->published < vote->published) {
          cached_dir_decref(v->vote_body);
          networkstatus_vote_free(v->vote);
          v->vote_body = new_cached_dir(vote_body, vote->published);
          v->vote = vote;
          *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(vote_body, vote->published);
  pending_vote->vote = vote;
  smartlist_add(pending_vote_list, pending_vote);

  *msg_out = "ok";
  return pending_vote;
 err:
  tor_free(vote_body);
  if (vote)
    networkstatus_vote_free(vote);
  if (!*msg_out)
    *msg_out = "Error adding vote";
  /*XXXX020 free other fields */
  return NULL;
}

/** DOCDOC */
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;
  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);
  /* XXXX020 see if there are enough to go ahead. */

  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());

  tor_free(pending_consensus_body);
  pending_consensus_body = consensus_body;

  return 0;
 err:
  if (votes)
    smartlist_free(votes);
  return -1;
}
+20 −2
Original line number Diff line number Diff line
@@ -368,9 +368,14 @@ typedef enum {
/** A connection to a directory server: upload a rendezvous
 * descriptor. */
#define DIR_PURPOSE_UPLOAD_RENDDESC 9
/** A connection to a directory server: upload a v3 networkstatus vote. */
#define DIR_PURPOSE_UPLOAD_VOTE 10
/** A connection to a directory server: fetch a v3 networkstatus vote. */
#define DIR_PURPOSE_FETCH_VOTE 11

/** Purpose for connection at a directory server. */
#define DIR_PURPOSE_SERVER 10
#define _DIR_PURPOSE_MAX 10
#define DIR_PURPOSE_SERVER 12
#define _DIR_PURPOSE_MAX 12

#define _EXIT_PURPOSE_MIN 1
/** This exit stream wants to do an ordinary connect. */
@@ -2765,6 +2770,9 @@ int routerstatus_format_entry(char *buf, size_t buf_len,
                              int first_line_only);
void dirserv_free_all(void);
void cached_dir_decref(cached_dir_t *d);
cached_dir_t *new_cached_dir(char *s, time_t published);

cached_dir_t *generate_v3_networkstatus(void);

#ifdef DIRSERV_PRIVATE
char *
@@ -2774,6 +2782,7 @@ format_networkstatus_vote(crypto_pk_env_t *private_key,

/********************************* dirvote.c ************************/

/* vote manipulation */
void networkstatus_vote_free(networkstatus_vote_t *ns);
char *networkstatus_compute_consensus(smartlist_t *votes,
                                      int total_authorities,
@@ -2784,6 +2793,7 @@ networkstatus_voter_info_t *networkstatus_get_voter_by_id(
                                       const char *identity);
int networkstatus_check_consensus_signature(networkstatus_vote_t *consensus);

/* cert manipulation */
void authority_cert_free(authority_cert_t *cert);
authority_cert_t *authority_cert_dup(authority_cert_t *cert);

@@ -2794,10 +2804,17 @@ typedef struct vote_timing_t {
  int vote_delay;
  int dist_delay;
} vote_timing_t;
/* vote scheduling */
void dirvote_get_preferred_voting_intervals(vote_timing_t *timing_out);
time_t dirvote_get_start_of_next_interval(time_t now, int interval);
void dirvote_recalculate_timing(time_t now);

/* invoked on timers and by outside triggers. */
void dirvote_perform_vote(void);
void dirvote_clear_pending_votes(void);
struct pending_vote_t * dirvote_add_vote(char *vote_body,const char **msg_out);
int dirvote_compute_consensus(void);

#ifdef DIRVOTE_PRIVATE
int networkstatus_check_voter_signature(networkstatus_vote_t *consensus,
                                        networkstatus_voter_info_t *voter,
@@ -3187,6 +3204,7 @@ void router_perform_bandwidth_test(int num_circs, time_t now);
int authdir_mode(or_options_t *options);
int authdir_mode_v1(or_options_t *options);
int authdir_mode_v2(or_options_t *options);
int authdir_mode_v3(or_options_t *options);
int authdir_mode_handles_descs(or_options_t *options);
int authdir_mode_publishes_statuses(or_options_t *options);
int authdir_mode_tests_reachability(or_options_t *options);
+8 −0
Original line number Diff line number Diff line
@@ -714,6 +714,14 @@ authdir_mode_v2(or_options_t *options)
{
  return authdir_mode(options) && options->V2AuthoritativeDir != 0;
}
/** Return true iff we believe ourselves to be a v3 authoritative
 * directory server.
 */
int
authdir_mode_v3(or_options_t *options)
{
  return authdir_mode(options) && options->V3AuthoritativeDir != 0;
}
/** Return true iff we are an authoritative directory server that
 * is willing to receive or serve descriptors on its dirport.
 */