Commit 8362f885 authored by Nick Mathewson's avatar Nick Mathewson 🤹
Browse files

Merge branch 'less_charbuf_rebased' into maint-0.2.4

Conflicts:
	src/or/dirserv.c
	src/or/dirserv.h
	src/test/test_dir.c
parents cd1cdae0 4b15606f
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
  o Code simplification and refactoring:
    - Avoid using character buffers when constructing most directory
      objects: this approach was unweildy and error-prone.  Instead,
      build smartlists of strings, and concatenate them when done.
+24 −0
Original line number Diff line number Diff line
@@ -1614,6 +1614,30 @@ crypto_digest_assign(crypto_digest_t *into,
  memcpy(into,from,sizeof(crypto_digest_t));
}


/** Given a list of strings in <b>lst</b>, set the <b>len_out</b>-byte digest
 * at <b>digest_out</b> to the hash of the concatenation of those strings,
 * plus the optional string <b>append</b>, computed with the algorithm
 * <b>alg</b>.
 * <b>out_len</b> must be \<= DIGEST256_LEN. */
void
crypto_digest_smartlist(char *digest_out, size_t len_out,
                        const smartlist_t *lst, const char *append,
                        digest_algorithm_t alg)
{
  crypto_digest_t *d;
  if (alg == DIGEST_SHA1)
    d = crypto_digest_new();
  else
    d = crypto_digest256_new(alg);
  SMARTLIST_FOREACH(lst, const char *, cp,
                    crypto_digest_add_bytes(d, cp, strlen(cp)));
  if (append)
    crypto_digest_add_bytes(d, append, strlen(append));
  crypto_digest_get_digest(d, digest_out, len_out);
  crypto_digest_free(d);
}

/** Compute the HMAC-SHA-1 of the <b>msg_len</b> bytes in <b>msg</b>, using
 * the <b>key</b> of length <b>key_len</b>.  Store the DIGEST_LEN-byte result
 * in <b>hmac_out</b>.
+4 −0
Original line number Diff line number Diff line
@@ -205,6 +205,10 @@ int crypto_digest(char *digest, const char *m, size_t len);
int crypto_digest256(char *digest, const char *m, size_t len,
                     digest_algorithm_t algorithm);
int crypto_digest_all(digests_t *ds_out, const char *m, size_t len);
struct smartlist_t;
void crypto_digest_smartlist(char *digest_out, size_t len_out,
                             const struct smartlist_t *lst, const char *append,
                             digest_algorithm_t alg);
const char *crypto_digest_algorithm_get_name(digest_algorithm_t alg);
int crypto_digest_algorithm_parse_name(const char *name);
crypto_digest_t *crypto_digest_new(void);
+60 −93
Original line number Diff line number Diff line
@@ -2311,11 +2311,10 @@ version_from_platform(const char *platform)
  return NULL;
}

/** Helper: write the router-status information in <b>rs</b> into <b>buf</b>,
 * which has at least <b>buf_len</b> free characters.  Do NUL-termination.
 * Use the same format as in network-status documents.  If <b>version</b> is
 * non-NULL, add a "v" line for the platform.  Return 0 on success, -1 on
 * failure.
/** 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.
 * 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
@@ -2326,25 +2325,25 @@ version_from_platform(const char *platform)
 *        it contains additional information for the vote.
 *   NS_CONTROL_PORT - Output a NS document for the control port
 */
int
routerstatus_format_entry(char *buf, size_t buf_len,
                          const routerstatus_t *rs, const char *version,
char *
routerstatus_format_entry(const routerstatus_t *rs, const char *version,
                          routerstatus_format_type_t format,
                          const vote_routerstatus_t *vrs)
{
  int r;
  char *cp;
  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 = NULL;

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

  r = tor_snprintf(buf, buf_len,
  chunks = smartlist_new();
  smartlist_add_asprintf(chunks,
                   "r %s %s %s%s%s %s %d %d\n",
                   rs->nickname,
                   identity64,
@@ -2354,11 +2353,6 @@ routerstatus_format_entry(char *buf, size_t buf_len,
                   fmt_addr32(rs->addr),
                   (int)rs->or_port,
                   (int)rs->dir_port);
  if (r<0) {
    log_warn(LD_BUG, "Not enough space in buffer.");
    return -1;
  }
  cp = buf + strlen(buf);

  /* 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
@@ -2367,25 +2361,18 @@ routerstatus_format_entry(char *buf, size_t buf_len,

  /* V3 microdesc consensuses don't have "a" lines. */
  if (format == NS_V3_CONSENSUS_MICRODESC)
    return 0;
    goto done;

  /* Possible "a" line. At most one for now. */
  if (!tor_addr_is_null(&rs->ipv6_addr)) {
    r = tor_snprintf(cp, buf_len - (cp-buf),
                     "a %s\n",
    smartlist_add_asprintf(chunks, "a %s\n",
                           fmt_addrport(&rs->ipv6_addr, rs->ipv6_orport));
    if (r<0) {
      log_warn(LD_BUG, "Not enough space in buffer.");
      return -1;
    }
    cp += strlen(cp);
  }

  if (format == NS_V3_CONSENSUS)
    return 0;
    goto done;

  /* NOTE: Whenever this list expands, be sure to increase MAX_FLAG_LINE_LEN*/
  r = tor_snprintf(cp, buf_len - (cp-buf),
  smartlist_add_asprintf(chunks,
                   "s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
                  /* These must stay in alphabetical order. */
                   rs->is_authority?" Authority":"",
@@ -2401,20 +2388,11 @@ routerstatus_format_entry(char *buf, size_t buf_len,
                   rs->is_unnamed?" Unnamed":"",
                   rs->is_v2_dir?" V2Dir":"",
                   rs->is_valid?" Valid":"");
  if (r<0) {
    log_warn(LD_BUG, "Not enough space in buffer.");
    return -1;
  }
  cp += strlen(cp);

  /* length of "opt v \n" */
#define V_LINE_OVERHEAD 7
  if (version && strlen(version) < MAX_V_LINE_LEN - V_LINE_OVERHEAD) {
    if (tor_snprintf(cp, buf_len - (cp-buf), "v %s\n", version)<0) {
      log_warn(LD_BUG, "Unable to print router version.");
      return -1;
    }
    cp += strlen(cp);
    smartlist_add_asprintf(chunks, "v %s\n", version);
  }

  if (format != NS_V2) {
@@ -2434,7 +2412,7 @@ routerstatus_format_entry(char *buf, size_t buf_len,
        log_warn(LD_BUG, "Cannot get any descriptor for %s "
            "(wanted descriptor %s).",
            id, dd);
        return -1;
        goto err;
      }

      /* This assert could fire for the control port, because
@@ -2469,39 +2447,32 @@ routerstatus_format_entry(char *buf, size_t buf_len,
      tor_assert(desc);
      bw_kb = router_get_advertised_bandwidth_capped(desc) / 1000;
    }
    r = tor_snprintf(cp, buf_len - (cp-buf),
                     "w Bandwidth=%d\n", bw_kb);
    smartlist_add_asprintf(chunks,
                     "w Bandwidth=%d", bw_kb);

    if (r<0) {
      log_warn(LD_BUG, "Not enough space in buffer.");
      return -1;
    }
    cp += strlen(cp);
    if (format == NS_V3_VOTE && vrs && vrs->has_measured_bw) {
      *--cp = '\0'; /* Kill "\n" */
      r = tor_snprintf(cp, buf_len - (cp-buf),
                       " Measured=%d\n", vrs->measured_bw_kb);
      if (r<0) {
        log_warn(LD_BUG, "Not enough space in buffer for weight line.");
        return -1;
      }
      cp += strlen(cp);
      smartlist_add_asprintf(chunks,
                       " Measured=%d", vrs->measured_bw_kb);
    }
    smartlist_add(chunks, tor_strdup("\n"));

    if (desc) {
      summary = policy_summarize(desc->exit_policy, AF_INET);
      r = tor_snprintf(cp, buf_len - (cp-buf), "p %s\n", summary);
      if (r<0) {
        log_warn(LD_BUG, "Not enough space in buffer.");
      smartlist_add_asprintf(chunks, "p %s\n", summary);
      tor_free(summary);
        return -1;
    }
      cp += strlen(cp);
      tor_free(summary);
  }

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

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

  return 0;
  return result;
}

/** Helper for sorting: compares two routerinfos first by address, and then by
@@ -3191,14 +3162,13 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
/** For v2 authoritative directories only: Replace the contents of
 * <b>the_v2_networkstatus</b> with a newly generated network status
 * object.  */
static cached_dir_t *
cached_dir_t *
generate_v2_networkstatus_opinion(void)
{
  cached_dir_t *r = NULL;
  size_t len, identity_pkey_len;
  size_t identity_pkey_len;
  char *status = NULL, *client_versions = NULL, *server_versions = NULL,
    *identity_pkey = NULL, *hostname = NULL;
  char *outp, *endp;
  const or_options_t *options = get_options();
  char fingerprint[FINGERPRINT_LEN+1];
  char published[ISO_TIME_LEN+1];
@@ -3217,6 +3187,7 @@ generate_v2_networkstatus_opinion(void)
  char *version_lines = NULL;
  smartlist_t *routers = NULL;
  digestmap_t *omit_as_sybil = NULL;
  smartlist_t *chunks = NULL;

  private_key = get_server_identity_key();

@@ -3255,12 +3226,8 @@ generate_v2_networkstatus_opinion(void)
    version_lines = tor_strdup("");
  }

  len = 4096+strlen(client_versions)+strlen(server_versions);
  len += identity_pkey_len*2;
  len += (RS_ENTRY_LEN)*smartlist_len(rl->routers);

  status = tor_malloc(len);
  tor_snprintf(status, len,
  chunks = smartlist_new();
  smartlist_add_asprintf(chunks,
               "network-status-version 2\n"
               "dir-source %s %s %d\n"
               "fingerprint %s\n"
@@ -3280,8 +3247,6 @@ generate_v2_networkstatus_opinion(void)
               versioning ? " Versions" : "",
               version_lines,
               identity_pkey);
  outp = status + strlen(status);
  endp = status + len;

  /* precompute this part, since we need it to decide what "stable"
   * means. */
@@ -3312,34 +3277,32 @@ generate_v2_networkstatus_opinion(void)
      if (digestmap_get(omit_as_sybil, ri->cache_info.identity_digest))
        clear_status_flags_on_sybil(&rs);

      if (routerstatus_format_entry(outp, endp-outp, &rs, version, NS_V2,
                                    NULL)) {
        log_warn(LD_BUG, "Unable to print router status.");
        tor_free(version);
        goto done;
      {
        char *rsf = routerstatus_format_entry(&rs, version, NS_V2, NULL);
        if (rsf)
          smartlist_add(chunks, rsf);
      }
      tor_free(version);
      outp += strlen(outp);
    }
  } SMARTLIST_FOREACH_END(ri);

  if (tor_snprintf(outp, endp-outp, "directory-signature %s\n",
                   options->Nickname)<0) {
    log_warn(LD_BUG, "Unable to write signature line.");
    goto done;
  }
  if (router_get_networkstatus_v2_hash(status, digest)<0) {
    log_warn(LD_BUG, "Unable to hash network status");
    goto done;
  }
  outp += strlen(outp);
  smartlist_add_asprintf(chunks, "directory-signature %s\n",
                         options->Nickname);

  crypto_digest_smartlist(digest, DIGEST_LEN, chunks, "", DIGEST_SHA1);

  note_crypto_pk_op(SIGN_DIR);
  if (router_append_dirobj_signature(outp,endp-outp,digest,DIGEST_LEN,
                                     private_key)<0) {
  {
    char *sig;
    if (!(sig = router_get_dirobj_signature(digest,DIGEST_LEN,
                                            private_key))) {
      log_warn(LD_BUG, "Unable to sign router status.");
      goto done;
    }
    smartlist_add(chunks, sig);
  }

  status = smartlist_join_strings(chunks, "", 0, NULL);

  {
    networkstatus_v2_t *ns;
@@ -3362,6 +3325,10 @@ generate_v2_networkstatus_opinion(void)
  }

 done:
  if (chunks) {
    SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
    smartlist_free(chunks);
  }
  tor_free(client_versions);
  tor_free(server_versions);
  tor_free(version_lines);
+2 −23
Original line number Diff line number Diff line
@@ -29,28 +29,6 @@

/** Maximum allowable length of a version line in a networkstatus. */
#define MAX_V_LINE_LEN 128
/** Length of "r Authority BadDirectory BadExit Exit Fast Guard HSDir Named
 * Running Stable Unnamed V2Dir Valid\n". */
#define MAX_FLAG_LINE_LEN 96
/** Length of "w" line for weighting.  Currently at most
 * "w Bandwidth=<uint32t> Measured=<uint32t>\n" */
#define MAX_WEIGHT_LINE_LEN (12+10+10+10+1)
/** Maximum length of an exit policy summary line. */
#define MAX_POLICY_LINE_LEN (3+MAX_EXITPOLICY_SUMMARY_LEN)
/** Amount of space to allocate for each entry: r, s, and v lines. */
#define RS_ENTRY_LEN                                                    \
  ( /* first line */                                                    \
   MAX_NICKNAME_LEN+BASE64_DIGEST_LEN*2+ISO_TIME_LEN+INET_NTOA_BUF_LEN+ \
   5*2 /* ports */ + 10 /* punctuation */ +                             \
   /* second line */                                                    \
   MAX_FLAG_LINE_LEN +                                                  \
   /* weight line */                                                    \
   MAX_WEIGHT_LINE_LEN +                                                \
   /* p line. */                                                        \
   MAX_POLICY_LINE_LEN +                                                \
   /* v line. */                                                        \
   MAX_V_LINE_LEN                                                       \
   )

int connection_dirserv_flushed_some(dir_connection_t *conn);

@@ -128,7 +106,7 @@ size_t dirserv_estimate_data_size(smartlist_t *fps, int is_serverdescs,
                                  int compressed);
size_t dirserv_estimate_microdesc_size(const smartlist_t *fps, int compressed);

int routerstatus_format_entry(char *buf, size_t buf_len,
char *routerstatus_format_entry(
                              const routerstatus_t *rs, const char *platform,
                              routerstatus_format_type_t format,
                              const vote_routerstatus_t *vrs);
@@ -154,6 +132,7 @@ int dirserv_get_measured_bw_cache_size(void);
int dirserv_query_measured_bw_cache_kb(const char *node_id, long *bw_out,
                                       time_t *as_of_out);
int dirserv_has_measured_bw(const char *node_id);
cached_dir_t *generate_v2_networkstatus_opinion(void);
#endif

int dirserv_read_measured_bandwidths(const char *from_file,
Loading