예제 #1
0
/** Generate a new certificate for our loaded or generated keys, and write it
 * to disk.  Return 0 on success, nonzero on failure. */
static int
generate_certificate(void)
{
  char buf[8192];
  time_t now = time(NULL);
  struct tm tm;
  char published[ISO_TIME_LEN+1];
  char expires[ISO_TIME_LEN+1];
  char fingerprint[FINGERPRINT_LEN+1];
  char *ident = key_to_string(identity_key);
  char *signing = key_to_string(signing_key);
  FILE *f;
  size_t signed_len;
  char digest[DIGEST_LEN];
  char signature[1024]; /* handles up to 8192-bit keys. */
  int r;

  get_fingerprint(identity_key, fingerprint);

  tor_localtime_r(&now, &tm);
  tm.tm_mon += months_lifetime;

  format_iso_time(published, now);
  format_iso_time(expires, mktime(&tm));

  tor_snprintf(buf, sizeof(buf),
               "dir-key-certificate-version 3"
               "%s%s"
               "\nfingerprint %s\n"
               "dir-key-published %s\n"
               "dir-key-expires %s\n"
               "dir-identity-key\n%s"
               "dir-signing-key\n%s"
               "dir-key-certification\n",
               address?"\ndir-address ":"", address?address:"",
               fingerprint, published, expires, ident, signing);
  tor_free(ident);
  tor_free(signing);
  signed_len = strlen(buf);
  SHA1((const unsigned char*)buf,signed_len,(unsigned char*)digest);

  r = RSA_private_encrypt(DIGEST_LEN, (unsigned char*)digest,
                          (unsigned char*)signature,
                          EVP_PKEY_get1_RSA(identity_key),
                          RSA_PKCS1_PADDING);
  strlcat(buf, "-----BEGIN SIGNATURE-----\n", sizeof(buf));
  signed_len = strlen(buf);
  base64_encode(buf+signed_len, sizeof(buf)-signed_len, signature, r);
  strlcat(buf, "-----END SIGNATURE-----\n", sizeof(buf));

  if (!(f = fopen(certificate_file, "w"))) {
    log_err(LD_GENERAL, "Couldn't open %s for writing: %s",
            certificate_file, strerror(errno));
    return 1;
  }

  fputs(buf, f);
  fclose(f);
  return 0;
}
예제 #2
0
파일: hibernate.c 프로젝트: ChatSecure/tor
/** Read stored accounting information from disk. Return 0 on success;
 * return -1 and change nothing on failure. */
static int
read_bandwidth_usage(void)
{
  or_state_t *state = get_or_state();

  {
    char *fname = get_datadir_fname("bw_accounting");
    unlink(fname);
    tor_free(fname);
  }

  if (!state)
    return -1;

  log_info(LD_ACCT, "Reading bandwidth accounting data from state file");
  n_bytes_read_in_interval = state->AccountingBytesReadInInterval;
  n_bytes_written_in_interval = state->AccountingBytesWrittenInInterval;
  n_seconds_active_in_interval = state->AccountingSecondsActive;
  interval_start_time = state->AccountingIntervalStart;
  expected_bandwidth_usage = state->AccountingExpectedUsage;

  /* Older versions of Tor (before 0.2.2.17-alpha or so) didn't generate these
   * fields. If you switch back and forth, you might get an
   * AccountingSoftLimitHitAt value from long before the most recent
   * interval_start_time.  If that's so, then ignore the softlimit-related
   * values. */
  if (state->AccountingSoftLimitHitAt > interval_start_time) {
    soft_limit_hit_at =  state->AccountingSoftLimitHitAt;
    n_bytes_at_soft_limit = state->AccountingBytesAtSoftLimit;
    n_seconds_to_hit_soft_limit = state->AccountingSecondsToReachSoftLimit;
  } else {
    soft_limit_hit_at = 0;
    n_bytes_at_soft_limit = 0;
    n_seconds_to_hit_soft_limit = 0;
  }

  {
    char tbuf1[ISO_TIME_LEN+1];
    char tbuf2[ISO_TIME_LEN+1];
    format_iso_time(tbuf1, state->LastWritten);
    format_iso_time(tbuf2, state->AccountingIntervalStart);

    log_info(LD_ACCT,
       "Successfully read bandwidth accounting info from state written at %s "
       "for interval starting at %s.  We have been active for %lu seconds in "
       "this interval.  At the start of the interval, we expected to use "
       "about %lu KB per second. ("U64_FORMAT" bytes read so far, "
       U64_FORMAT" bytes written so far)",
       tbuf1, tbuf2,
       (unsigned long)n_seconds_active_in_interval,
       (unsigned long)(expected_bandwidth_usage*1024/60),
       U64_PRINTF_ARG(n_bytes_read_in_interval),
       U64_PRINTF_ARG(n_bytes_written_in_interval));
  }

  return 0;
}
예제 #3
0
파일: hibernate.c 프로젝트: pcostamagna/tor
/** Called when hibernate_end_time has arrived. */
static void
hibernate_end_time_elapsed(time_t now)
{
  char buf[ISO_TIME_LEN+1];

  /* The interval has ended, or it is wakeup time.  Find out which. */
  accounting_run_housekeeping(now);
  if (interval_wakeup_time <= now) {
    /* The interval hasn't changed, but interval_wakeup_time has passed.
     * It's time to wake up and start being a server. */
    hibernate_end(HIBERNATE_STATE_LIVE);
    return;
  } else {
    /* The interval has changed, and it isn't time to wake up yet. */
    hibernate_end_time = interval_wakeup_time;
    format_iso_time(buf,interval_wakeup_time);
    if (hibernate_state != HIBERNATE_STATE_DORMANT) {
      /* We weren't sleeping before; we should sleep now. */
      log_notice(LD_ACCT,
                 "Accounting period ended. Commencing hibernation until "
                 "%s GMT", buf);
      hibernate_go_dormant(now);
    } else {
      log_notice(LD_ACCT,
             "Accounting period ended. This period, we will hibernate"
             " until %s GMT",buf);
    }
  }
}
예제 #4
0
/** 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
 * annotations. */
static ssize_t
dump_microdescriptor(FILE *f, microdesc_t *md, size_t *annotation_len_out)
{
  ssize_t r = 0;
  size_t written;
  /* XXXX drops unknown annotations. */
  if (md->last_listed) {
    char buf[ISO_TIME_LEN+1];
    char annotation[ISO_TIME_LEN+32];
    format_iso_time(buf, md->last_listed);
    tor_snprintf(annotation, sizeof(annotation), "@last-listed %s\n", buf);
    if (fputs(annotation, f) < 0) {
      log_warn(LD_DIR,
               "Couldn't write microdescriptor annotation: %s",
               strerror(ferror(f)));
      return -1;
    }
    r += strlen(annotation);
    *annotation_len_out = r;
  } else {
    *annotation_len_out = 0;
  }

  md->off = (off_t) ftell(f);
  written = fwrite(md->body, 1, md->bodylen, f);
  if (written != md->bodylen) {
    log_warn(LD_DIR,
             "Couldn't dump microdescriptor (wrote %lu out of %lu): %s",
             (unsigned long)written, (unsigned long)md->bodylen,
             strerror(ferror(f)));
    return -1;
  }
  r += md->bodylen;
  return r;
}
예제 #5
0
/* Return the time we should expire the state file created at <b>now</b>.
 * We expire the state file in the beginning of the next protocol run. */
STATIC time_t
get_state_valid_until_time(time_t now)
{
  int total_rounds = SHARED_RANDOM_N_ROUNDS * SHARED_RANDOM_N_PHASES;
  int current_round, voting_interval, rounds_left;
  time_t valid_until, beginning_of_current_round;

  voting_interval = get_voting_interval();
  /* Find the time the current round started. */
  beginning_of_current_round = get_start_time_of_current_round();

  /* Find how many rounds are left till the end of the protocol run */
  current_round = (now / voting_interval) % total_rounds;
  rounds_left = total_rounds - current_round;

  /* To find the valid-until time now, take the start time of the current
   * round and add to it the time it takes for the leftover rounds to
   * complete. */
  valid_until = beginning_of_current_round + (rounds_left * voting_interval);

  { /* Logging */
    char tbuf[ISO_TIME_LEN + 1];
    format_iso_time(tbuf, valid_until);
    log_debug(LD_DIR, "SR: Valid until time for state set to %s.", tbuf);
  }

  return valid_until;
}
예제 #6
0
파일: hibernate.c 프로젝트: pcostamagna/tor
/** Read stored accounting information from disk. Return 0 on success;
 * return -1 and change nothing on failure. */
static int
read_bandwidth_usage(void)
{
  or_state_t *state = get_or_state();

  {
    char *fname = get_datadir_fname("bw_accounting");
    unlink(fname);
    tor_free(fname);
  }

  if (!state)
    return -1;

  /* Okay; it looks like the state file is more up-to-date than the
   * bw_accounting file, or the bw_accounting file is nonexistent,
   * or the bw_accounting file is corrupt.
   */
  log_info(LD_ACCT, "Reading bandwidth accounting data from state file");
  n_bytes_read_in_interval = state->AccountingBytesReadInInterval;
  n_bytes_written_in_interval = state->AccountingBytesWrittenInInterval;
  n_seconds_active_in_interval = state->AccountingSecondsActive;
  interval_start_time = state->AccountingIntervalStart;
  expected_bandwidth_usage = state->AccountingExpectedUsage;

  {
    char tbuf1[ISO_TIME_LEN+1];
    char tbuf2[ISO_TIME_LEN+1];
    format_iso_time(tbuf1, state->LastWritten);
    format_iso_time(tbuf2, state->AccountingIntervalStart);

    log_info(LD_ACCT,
       "Successfully read bandwidth accounting info from state written at %s "
       "for interval starting at %s.  We have been active for %lu seconds in "
       "this interval.  At the start of the interval, we expected to use "
       "about %lu KB per second. ("U64_FORMAT" bytes read so far, "
       U64_FORMAT" bytes written so far)",
       tbuf1, tbuf2,
       (unsigned long)n_seconds_active_in_interval,
       (unsigned long)(expected_bandwidth_usage*1024/60),
       U64_PRINTF_ARG(n_bytes_read_in_interval),
       U64_PRINTF_ARG(n_bytes_written_in_interval));
  }

  return 0;
}
예제 #7
0
파일: hibernate.c 프로젝트: 4ZM/Tor
/** Helper function: called when we get a GETINFO request for an
 * accounting-related key on the control connection <b>conn</b>.  If we can
 * answer the request for <b>question</b>, then set *<b>answer</b> to a newly
 * allocated string holding the result.  Otherwise, set *<b>answer</b> to
 * NULL. */
int
getinfo_helper_accounting(control_connection_t *conn,
                          const char *question, char **answer,
                          const char **errmsg)
{
  (void) conn;
  (void) errmsg;
  if (!strcmp(question, "accounting/enabled")) {
    *answer = tor_strdup(accounting_is_enabled(get_options()) ? "1" : "0");
  } else if (!strcmp(question, "accounting/hibernating")) {
    if (hibernate_state == HIBERNATE_STATE_DORMANT)
      *answer = tor_strdup("hard");
    else if (hibernate_state == HIBERNATE_STATE_LOWBANDWIDTH)
      *answer = tor_strdup("soft");
    else
      *answer = tor_strdup("awake");
  } else if (!strcmp(question, "accounting/bytes")) {
    *answer = tor_malloc(32);
    tor_snprintf(*answer, 32, U64_FORMAT" "U64_FORMAT,
                 U64_PRINTF_ARG(n_bytes_read_in_interval),
                 U64_PRINTF_ARG(n_bytes_written_in_interval));
  } else if (!strcmp(question, "accounting/bytes-left")) {
    uint64_t limit = get_options()->AccountingMax;
    uint64_t read_left = 0, write_left = 0;
    if (n_bytes_read_in_interval < limit)
      read_left = limit - n_bytes_read_in_interval;
    if (n_bytes_written_in_interval < limit)
      write_left = limit - n_bytes_written_in_interval;
    *answer = tor_malloc(64);
    tor_snprintf(*answer, 64, U64_FORMAT" "U64_FORMAT,
                 U64_PRINTF_ARG(read_left), U64_PRINTF_ARG(write_left));
  } else if (!strcmp(question, "accounting/interval-start")) {
    *answer = tor_malloc(ISO_TIME_LEN+1);
    format_iso_time(*answer, interval_start_time);
  } else if (!strcmp(question, "accounting/interval-wake")) {
    *answer = tor_malloc(ISO_TIME_LEN+1);
    format_iso_time(*answer, interval_wakeup_time);
  } else if (!strcmp(question, "accounting/interval-end")) {
    *answer = tor_malloc(ISO_TIME_LEN+1);
    format_iso_time(*answer, interval_end_time);
  } else {
    *answer = NULL;
  }
  return 0;
}
예제 #8
0
/* Return a statically allocated string representing yesterday's date
 * in ISO format. We use it so that state file items are not found to
 * be outdated. */
const char *
get_yesterday_date_str(void)
{
  static char buf[ISO_TIME_LEN+1];

  time_t yesterday = time(NULL) - 24*60*60;
  format_iso_time(buf, yesterday);
  return buf;
}
예제 #9
0
/* time_t to ISO 8601 */
int strtime_iso(const time_t *t, int flags, char *buf, size_t bufsz)
{
	struct tm tm;

	if (flags & ISO_8601_GMTIME)
		tm = *gmtime(t);
	else
		tm = *localtime(t);
	return format_iso_time(&tm, 0, flags, buf, bufsz);
}
예제 #10
0
/* timeval to ISO 8601 */
int strtimeval_iso(struct timeval *tv, int flags, char *buf, size_t bufsz)
{
	struct tm tm;

	if (flags & ISO_8601_GMTIME)
		tm = *gmtime(&tv->tv_sec);
	else
		tm = *localtime(&tv->tv_sec);
	return format_iso_time(&tm, tv->tv_usec, flags, buf, bufsz);
}
예제 #11
0
파일: microdesc.c 프로젝트: jfrazelle/tor
/** 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
 * annotations. */
static ssize_t
dump_microdescriptor(int fd, microdesc_t *md, size_t *annotation_len_out)
{
  ssize_t r = 0;
  ssize_t written;
  if (md->body == NULL) {
    *annotation_len_out = 0;
    return 0;
  }
  /* XXXX drops unknown annotations. */
  if (md->last_listed) {
    char buf[ISO_TIME_LEN+1];
    char annotation[ISO_TIME_LEN+32];
    format_iso_time(buf, md->last_listed);
    tor_snprintf(annotation, sizeof(annotation), "@last-listed %s\n", buf);
    if (write_all_to_fd(fd, annotation, strlen(annotation)) < 0) {
      log_warn(LD_DIR,
               "Couldn't write microdescriptor annotation: %s",
               strerror(errno));
      return -1;
    }
    r += strlen(annotation);
    *annotation_len_out = r;
  } else {
    *annotation_len_out = 0;
  }

  md->off = tor_fd_getpos(fd);
  warn_if_nul_found(md->body, md->bodylen, (int64_t) md->off,
                    "dumping a microdescriptor");
  written = write_all_to_fd(fd, md->body, md->bodylen);
  if (written != (ssize_t)md->bodylen) {
    written = written < 0 ? 0 : written;
    log_warn(LD_DIR,
             "Couldn't dump microdescriptor (wrote %ld out of %lu): %s",
             (long)written, (unsigned long)md->bodylen,
             strerror(errno));
    return -1;
  }
  r += md->bodylen;
  return r;
}
예제 #12
0
파일: hibernate.c 프로젝트: pcostamagna/tor
/** Based on our interval and our estimated bandwidth, choose a
 * deterministic (but random-ish) time to wake up. */
static void
accounting_set_wakeup_time(void)
{
  char buf[ISO_TIME_LEN+1];
  char digest[DIGEST_LEN];
  crypto_digest_env_t *d_env;
  int time_in_interval;
  uint64_t time_to_exhaust_bw;
  int time_to_consider;

  if (! identity_key_is_set()) {
    if (init_keys() < 0) {
      log_err(LD_BUG, "Error initializing keys");
      tor_assert(0);
    }
  }

  format_iso_time(buf, interval_start_time);
  crypto_pk_get_digest(get_identity_key(), digest);

  d_env = crypto_new_digest_env();
  crypto_digest_add_bytes(d_env, buf, ISO_TIME_LEN);
  crypto_digest_add_bytes(d_env, digest, DIGEST_LEN);
  crypto_digest_get_digest(d_env, digest, DIGEST_LEN);
  crypto_free_digest_env(d_env);

  if (!expected_bandwidth_usage) {
    char buf1[ISO_TIME_LEN+1];
    char buf2[ISO_TIME_LEN+1];
    format_local_iso_time(buf1, interval_start_time);
    format_local_iso_time(buf2, interval_end_time);
    time_to_exhaust_bw = GUESS_TIME_TO_USE_BANDWIDTH;
    interval_wakeup_time = interval_start_time;

    log_notice(LD_ACCT,
           "Configured hibernation.  This interval begins at %s "
           "and ends at %s.  We have no prior estimate for bandwidth, so "
           "we will start out awake and hibernate when we exhaust our quota.",
           buf1, buf2);
    return;
  }

  time_in_interval = (int)(interval_end_time - interval_start_time);

  time_to_exhaust_bw =
    (get_options()->AccountingMax/expected_bandwidth_usage)*60;
  if (time_to_exhaust_bw > TIME_MAX) {
    time_to_exhaust_bw = TIME_MAX;
    time_to_consider = 0;
  } else {
    time_to_consider = time_in_interval - (int)time_to_exhaust_bw;
  }

  if (time_to_consider<=0) {
    interval_wakeup_time = interval_start_time;
  } else {
    /* XXX can we simplify this just by picking a random (non-deterministic)
     * time to be up? If we go down and come up, then we pick a new one. Is
     * that good enough? -RD */

    /* This is not a perfectly unbiased conversion, but it is good enough:
     * in the worst case, the first half of the day is 0.06 percent likelier
     * to be chosen than the last half. */
    interval_wakeup_time = interval_start_time +
      (get_uint32(digest) % time_to_consider);

    format_iso_time(buf, interval_wakeup_time);
  }

  {
    char buf1[ISO_TIME_LEN+1];
    char buf2[ISO_TIME_LEN+1];
    char buf3[ISO_TIME_LEN+1];
    char buf4[ISO_TIME_LEN+1];
    time_t down_time;
    if (interval_wakeup_time+time_to_exhaust_bw > TIME_MAX)
      down_time = TIME_MAX;
    else
      down_time = (time_t)(interval_wakeup_time+time_to_exhaust_bw);
    if (down_time>interval_end_time)
      down_time = interval_end_time;
    format_local_iso_time(buf1, interval_start_time);
    format_local_iso_time(buf2, interval_wakeup_time);
    format_local_iso_time(buf3, down_time);
    format_local_iso_time(buf4, interval_end_time);

    log_notice(LD_ACCT,
           "Configured hibernation.  This interval began at %s; "
           "the scheduled wake-up time %s %s; "
           "we expect%s to exhaust our quota for this interval around %s; "
           "the next interval begins at %s (all times local)",
           buf1,
           time(NULL)<interval_wakeup_time?"is":"was", buf2,
           time(NULL)<down_time?"":"ed", buf3,
           buf4);
  }
}
예제 #13
0
/** Helper: write the router-status information in <b>rs</b> into a newly
 * allocated character buffer.  Use the same format as in network-status
 * documents.  If <b>version</b> is non-NULL, add a "v" line for the platform.
 *
 * consensus_method is the current consensus method when format is
 * NS_V3_CONSENSUS or NS_V3_CONSENSUS_MICRODESC. It is ignored for other
 * formats: pass ROUTERSTATUS_FORMAT_NO_CONSENSUS_METHOD.
 *
 * Return 0 on success, -1 on failure.
 *
 * The format argument has one of the following values:
 *   NS_V2 - Output an entry suitable for a V2 NS opinion document
 *   NS_V3_CONSENSUS - Output the first portion of a V3 NS consensus entry
 *        for consensus_method.
 *   NS_V3_CONSENSUS_MICRODESC - Output the first portion of a V3 microdesc
 *        consensus entry for consensus_method.
 *   NS_V3_VOTE - Output a complete V3 NS vote. If <b>vrs</b> is present,
 *        it contains additional information for the vote.
 *   NS_CONTROL_PORT - Output a NS document for the control port.
 */
char *
routerstatus_format_entry(const routerstatus_t *rs, const char *version,
                          const char *protocols,
                          routerstatus_format_type_t format,
                          int consensus_method,
                          const vote_routerstatus_t *vrs)
{
  char *summary;
  char *result = NULL;

  char published[ISO_TIME_LEN+1];
  char identity64[BASE64_DIGEST_LEN+1];
  char digest64[BASE64_DIGEST_LEN+1];
  smartlist_t *chunks = smartlist_new();

  format_iso_time(published, rs->published_on);
  digest_to_base64(identity64, rs->identity_digest);
  digest_to_base64(digest64, rs->descriptor_digest);

  smartlist_add_asprintf(chunks,
                   "r %s %s %s%s%s %s %d %d\n",
                   rs->nickname,
                   identity64,
                   (format==NS_V3_CONSENSUS_MICRODESC)?"":digest64,
                   (format==NS_V3_CONSENSUS_MICRODESC)?"":" ",
                   published,
                   fmt_addr32(rs->addr),
                   (int)rs->or_port,
                   (int)rs->dir_port);

  /* TODO: Maybe we want to pass in what we need to build the rest of
   * this here, instead of in the caller. Then we could use the
   * networkstatus_type_t values, with an additional control port value
   * added -MP */

  /* V3 microdesc consensuses only have "a" lines in later consensus methods
   */
  if (format == NS_V3_CONSENSUS_MICRODESC &&
      consensus_method < MIN_METHOD_FOR_A_LINES_IN_MICRODESC_CONSENSUS)
    goto done;

  /* Possible "a" line. At most one for now. */
  if (!tor_addr_is_null(&rs->ipv6_addr)) {
    smartlist_add_asprintf(chunks, "a %s\n",
                           fmt_addrport(&rs->ipv6_addr, rs->ipv6_orport));
  }

  if (format == NS_V3_CONSENSUS || format == NS_V3_CONSENSUS_MICRODESC)
    goto done;

  smartlist_add_asprintf(chunks,
                   "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_flagged_running?" Running":"",
                   rs->is_stable?" Stable":"",
                   rs->is_staledesc?" StaleDesc":"",
                   rs->is_v2_dir?" V2Dir":"",
                   rs->is_valid?" Valid":"");

  /* length of "opt v \n" */
#define V_LINE_OVERHEAD 7
  if (version && strlen(version) < MAX_V_LINE_LEN - V_LINE_OVERHEAD) {
    smartlist_add_asprintf(chunks, "v %s\n", version);
  }
  if (protocols) {
    smartlist_add_asprintf(chunks, "pr %s\n", protocols);
  }

  if (format != NS_V2) {
    const routerinfo_t* desc = router_get_by_id_digest(rs->identity_digest);
    uint32_t bw_kb;

    if (format != NS_CONTROL_PORT) {
      /* Blow up more or less nicely if we didn't get anything or not the
       * thing we expected.
       */
      if (!desc) {
        char id[HEX_DIGEST_LEN+1];
        char dd[HEX_DIGEST_LEN+1];

        base16_encode(id, sizeof(id), rs->identity_digest, DIGEST_LEN);
        base16_encode(dd, sizeof(dd), rs->descriptor_digest, DIGEST_LEN);
        log_warn(LD_BUG, "Cannot get any descriptor for %s "
            "(wanted descriptor %s).",
            id, dd);
        goto err;
      }

      /* This assert could fire for the control port, because
       * it can request NS documents before all descriptors
       * have been fetched. Therefore, we only do this test when
       * format != NS_CONTROL_PORT. */
      if (tor_memneq(desc->cache_info.signed_descriptor_digest,
            rs->descriptor_digest,
            DIGEST_LEN)) {
        char rl_d[HEX_DIGEST_LEN+1];
        char rs_d[HEX_DIGEST_LEN+1];
        char id[HEX_DIGEST_LEN+1];

        base16_encode(rl_d, sizeof(rl_d),
            desc->cache_info.signed_descriptor_digest, DIGEST_LEN);
        base16_encode(rs_d, sizeof(rs_d), rs->descriptor_digest, DIGEST_LEN);
        base16_encode(id, sizeof(id), rs->identity_digest, DIGEST_LEN);
        log_err(LD_BUG, "descriptor digest in routerlist does not match "
            "the one in routerstatus: %s vs %s "
            "(router %s)\n",
            rl_d, rs_d, id);

        tor_assert(tor_memeq(desc->cache_info.signed_descriptor_digest,
              rs->descriptor_digest,
              DIGEST_LEN));
      }
    }

    if (format == NS_CONTROL_PORT && rs->has_bandwidth) {
      bw_kb = rs->bandwidth_kb;
    } else {
      tor_assert(desc);
      bw_kb = router_get_advertised_bandwidth_capped(desc) / 1000;
    }
    smartlist_add_asprintf(chunks,
                     "w Bandwidth=%d", bw_kb);

    if (format == NS_V3_VOTE && vrs && vrs->has_measured_bw) {
      smartlist_add_asprintf(chunks,
                       " Measured=%d", vrs->measured_bw_kb);
    }
    /* Write down guardfraction information if we have it. */
    if (format == NS_V3_VOTE && vrs && vrs->status.has_guardfraction) {
      smartlist_add_asprintf(chunks,
                             " GuardFraction=%d",
                             vrs->status.guardfraction_percentage);
    }

    smartlist_add_strdup(chunks, "\n");

    if (desc) {
      summary = policy_summarize(desc->exit_policy, AF_INET);
      smartlist_add_asprintf(chunks, "p %s\n", summary);
      tor_free(summary);
    }

    if (format == NS_V3_VOTE && vrs) {
      if (tor_mem_is_zero((char*)vrs->ed25519_id, ED25519_PUBKEY_LEN)) {
        smartlist_add_strdup(chunks, "id ed25519 none\n");
      } else {
        char ed_b64[BASE64_DIGEST256_LEN+1];
        digest256_to_base64(ed_b64, (const char*)vrs->ed25519_id);
        smartlist_add_asprintf(chunks, "id ed25519 %s\n", ed_b64);
      }
    }
  }

 done:
  result = smartlist_join_strings(chunks, "", 0, NULL);

 err:
  SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
  smartlist_free(chunks);

  return result;
}
예제 #14
0
/* struct tm to ISO 8601 */
int strtm_iso(struct tm *tm, int flags, char *buf, size_t bufsz)
{
	return format_iso_time(tm, 0, flags, buf, bufsz);
}
예제 #15
0
/* Update the current SR state as needed for the upcoming voting round at
 * <b>valid_after</b>. */
void
sr_state_update(time_t valid_after)
{
  sr_phase_t next_phase;

  if (BUG(!sr_state))
    return;

  /* Don't call this function twice in the same voting period. */
  if (valid_after <= sr_state->valid_after) {
    log_info(LD_DIR, "SR: Asked to update state twice. Ignoring.");
    return;
  }

  /* Get phase of upcoming round. */
  next_phase = get_sr_protocol_phase(valid_after);

  /* If we are transitioning to a new protocol phase, prepare the stage. */
  if (is_phase_transition(next_phase)) {
    if (next_phase == SR_PHASE_COMMIT) {
      /* Going into commit phase means we are starting a new protocol run. */
      new_protocol_run(valid_after);
    }
    /* Set the new phase for this round */
    sr_state->phase = next_phase;
  } else if (sr_state->phase == SR_PHASE_COMMIT &&
             digestmap_size(sr_state->commits) == 0) {
    /* We are _NOT_ in a transition phase so if we are in the commit phase
     * and have no commit, generate one. Chances are that we are booting up
     * so let's have a commit in our state for the next voting period. */
    sr_commit_t *our_commit =
      sr_generate_our_commit(valid_after, get_my_v3_authority_cert());
    if (our_commit) {
      /* Add our commitment to our state. In case we are unable to create one
       * (highly unlikely), we won't vote for this protocol run since our
       * commitment won't be in our state. */
      sr_state_add_commit(our_commit);
    }
  }

  sr_state_set_valid_after(valid_after);

  /* Count the current round */
  if (sr_state->phase == SR_PHASE_COMMIT) {
    /* invariant check: we've not entered reveal phase yet */
    if (BUG(sr_state->n_reveal_rounds != 0))
      return;
    sr_state->n_commit_rounds++;
  } else {
    sr_state->n_reveal_rounds++;
  }

  { /* Debugging. */
    char tbuf[ISO_TIME_LEN + 1];
    format_iso_time(tbuf, valid_after);
    log_info(LD_DIR, "SR: State prepared for upcoming voting period (%s). "
             "Upcoming phase is %s (counters: %d commit & %d reveal rounds).",
             tbuf, get_phase_str(sr_state->phase),
             sr_state->n_commit_rounds, sr_state->n_reveal_rounds);
  }
}