Commit 50beb81d authored by Andrea Shepard's avatar Andrea Shepard
Browse files

Merge branch 'maint-0.2.4'

parents 82ab33c9 aaa3a085
Loading
Loading
Loading
Loading

changes/bug5595

0 → 100644
+8 −0
Original line number Diff line number Diff line
  o Critical bugfixes:
    - Distinguish downloading an authority certificate by identity digest from
      downloading one by identity digest/signing key digest pair; formerly we
      always request them only by identity digest and get the newest one even
      when we wanted one with a different signing key.  Then we would complain
      about being given a certificate we already had, and never get the one we
      really wanted.  Now we use the "fp-sk/" resource as well as the "fp/"
      resource to request the one we want.  Fixes bug 5595.
+1 −0
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ LIBTOR_OBJECTS = \
  dirvote.obj \
  dns.obj \
  dnsserv.obj \
  fp_pair.obj \
  entrynodes.obj \
  geoip.obj \
  hibernate.obj \
+59 −14
Original line number Diff line number Diff line
@@ -856,19 +856,43 @@ connection_dir_bridge_routerdesc_failed(dir_connection_t *conn)
static void
connection_dir_download_cert_failed(dir_connection_t *conn, int status)
{
  const char *fp_pfx = "fp/";
  const char *fpsk_pfx = "fp-sk/";
  smartlist_t *failed;
  tor_assert(conn->base_.purpose == DIR_PURPOSE_FETCH_CERTIFICATE);

  if (!conn->requested_resource)
    return;
  failed = smartlist_new();
  dir_split_resource_into_fingerprints(conn->requested_resource+3,
  /*
   * We have two cases download by fingerprint (resource starts
   * with "fp/") or download by fingerprint/signing key pair
   * (resource starts with "fp-sk/").
   */
  if (!strcmpstart(conn->requested_resource, fp_pfx)) {
    /* Download by fingerprint case */
    dir_split_resource_into_fingerprints(conn->requested_resource +
                                         strlen(fp_pfx),
                                         failed, NULL, DSR_HEX);
  SMARTLIST_FOREACH(failed, char *, cp,
  {
    authority_cert_dl_failed(cp, status);
    SMARTLIST_FOREACH_BEGIN(failed, char *, cp) {
      /* Null signing key digest indicates download by fp only */
      authority_cert_dl_failed(cp, NULL, status);
      tor_free(cp);
  });
    } SMARTLIST_FOREACH_END(cp);
  } else if (!strcmpstart(conn->requested_resource, fpsk_pfx)) {
    /* Download by (fp,sk) pairs */
    dir_split_resource_into_fingerprint_pairs(conn->requested_resource +
                                              strlen(fpsk_pfx), failed);
    SMARTLIST_FOREACH_BEGIN(failed, fp_pair_t *, cp) {
      authority_cert_dl_failed(cp->first, cp->second, status);
      tor_free(cp);
    } SMARTLIST_FOREACH_END(cp);
  } else {
    log_warn(LD_DIR,
             "Don't know what to do with failure for cert fetch %s",
             conn->requested_resource);
  }

  smartlist_free(failed);

  update_certificate_downloads(time(NULL));
@@ -1634,6 +1658,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
                       conn->base_.purpose == DIR_PURPOSE_FETCH_MICRODESC);
  int was_compressed=0;
  time_t now = time(NULL);
  int src_code;

  switch (connection_fetch_from_buf_http(TO_CONN(conn),
                              &headers, MAX_HEADERS_SIZE,
@@ -1902,7 +1927,20 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
    }
    log_info(LD_DIR,"Received authority certificates (size %d) from server "
             "'%s:%d'", (int)body_len, conn->base_.address, conn->base_.port);
    if (trusted_dirs_load_certs_from_string(body, 0, 1)<0) {

    /*
     * Tell trusted_dirs_load_certs_from_string() whether it was by fp
     * or fp-sk pair.
     */
    src_code = -1;
    if (!strcmpstart(conn->requested_resource, "fp/")) {
      src_code = TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_DIGEST;
    } else if (!strcmpstart(conn->requested_resource, "fp-sk/")) {
      src_code = TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_SK_DIGEST;
    }

    if (src_code != -1) {
      if (trusted_dirs_load_certs_from_string(body, src_code, 1)<0) {
        log_warn(LD_DIR, "Unable to parse fetched certificates");
        /* if we fetched more than one and only some failed, the successful
         * ones got flushed to disk so it's safe to call this on them */
@@ -1911,6 +1949,13 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
        directory_info_has_arrived(now, 0);
        log_info(LD_DIR, "Successfully loaded certificates from fetch.");
      }
    } else {
      log_warn(LD_DIR,
               "Couldn't figure out what to do with fetched certificates for "
               "unknown resource %s",
               conn->requested_resource);
      connection_dir_download_cert_failed(conn, status_code);
    }
  }
  if (conn->base_.purpose == DIR_PURPOSE_FETCH_STATUS_VOTE) {
    const char *msg;
+1 −1
Original line number Diff line number Diff line
@@ -2963,7 +2963,7 @@ dirvote_add_vote(const char *vote_body, const char **msg_out, int *status_out)
    /* Hey, it's a new cert! */
    trusted_dirs_load_certs_from_string(
                               vote->cert->cache_info.signed_descriptor_body,
                               0 /* from_store */, 1 /*flush*/);
                               TRUSTED_DIRS_CERTS_SRC_FROM_VOTE, 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.");

src/or/fp_pair.c

0 → 100644
+308 −0
Original line number Diff line number Diff line
/* Copyright (c) 2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */

#include "or.h"
#include "fp_pair.h"

/* Define fp_pair_map_t structures */

struct fp_pair_map_entry_s {
  HT_ENTRY(fp_pair_map_entry_s) node;
  void *val;
  fp_pair_t key;
};

struct fp_pair_map_s {
  HT_HEAD(fp_pair_map_impl, fp_pair_map_entry_s) head;
};

/*
 * Hash function and equality checker for fp_pair_map_t
 */

/** Compare fp_pair_entry_t objects by key value. */
static INLINE int
fp_pair_map_entries_eq(const fp_pair_map_entry_t *a,
                       const fp_pair_map_entry_t *b)
{
  return tor_memeq(&(a->key), &(b->key), sizeof(fp_pair_t));
}

/** Return a hash value for an fp_pair_entry_t. */
static INLINE unsigned int
fp_pair_map_entry_hash(const fp_pair_map_entry_t *a)
{
  const uint32_t *p;
  unsigned int hash;

  p = (const uint32_t *)(a->key.first);
  /* Hashes are 20 bytes long, so 5 times uint32_t */
  hash = p[0] ^ p[1] ^ p[2] ^ p[3] ^ p[4];
  /* Now XOR in the second fingerprint */
  p = (const uint32_t *)(a->key.second);
  hash ^= p[0] ^ p[1] ^ p[2] ^ p[3] ^ p[4];

  return hash;
}

/*
 * Hash table functions for fp_pair_map_t
 */

HT_PROTOTYPE(fp_pair_map_impl, fp_pair_map_entry_s, node,
             fp_pair_map_entry_hash, fp_pair_map_entries_eq)
HT_GENERATE(fp_pair_map_impl, fp_pair_map_entry_s, node,
            fp_pair_map_entry_hash, fp_pair_map_entries_eq,
            0.6, tor_malloc, tor_realloc, tor_free)

/** Constructor to create a new empty map from fp_pair_t to void *
 */

fp_pair_map_t *
fp_pair_map_new(void)
{
  fp_pair_map_t *result;

  result = tor_malloc(sizeof(fp_pair_map_t));
  HT_INIT(fp_pair_map_impl, &result->head);
  return result;
}

/** Set the current value for key to val; returns the previous
 * value for key if one was set, or NULL if one was not.
 */

void *
fp_pair_map_set(fp_pair_map_t *map, const fp_pair_t *key, void *val)
{
  fp_pair_map_entry_t *resolve;
  fp_pair_map_entry_t search;
  void *oldval;

  tor_assert(map);
  tor_assert(key);
  tor_assert(val);

  memcpy(&(search.key), key, sizeof(*key));
  resolve = HT_FIND(fp_pair_map_impl, &(map->head), &search);
  if (resolve) {
    oldval = resolve->val;
    resolve->val = val;
  } else {
    resolve = tor_malloc_zero(sizeof(fp_pair_map_entry_t));
    memcpy(&(resolve->key), key, sizeof(*key));
    resolve->val = val;
    HT_INSERT(fp_pair_map_impl, &(map->head), resolve);
    oldval = NULL;
  }

  return oldval;
}

/** Set the current value for the key (first, second) to val; returns
 * the previous value for key if one was set, or NULL if one was not.
 */

void *
fp_pair_map_set_by_digests(fp_pair_map_t *map,
                           const char *first, const char *second,
                           void *val)
{
  fp_pair_t k;

  tor_assert(first);
  tor_assert(second);

  memcpy(k.first, first, DIGEST_LEN);
  memcpy(k.second, second, DIGEST_LEN);

  return fp_pair_map_set(map, &k, val);
}

/** Return the current value associated with key, or NULL if no value is set.
 */

void *
fp_pair_map_get(const fp_pair_map_t *map, const fp_pair_t *key)
{
  fp_pair_map_entry_t *resolve;
  fp_pair_map_entry_t search;
  void *val = NULL;

  tor_assert(map);
  tor_assert(key);

  memcpy(&(search.key), key, sizeof(*key));
  resolve = HT_FIND(fp_pair_map_impl, &(map->head), &search);
  if (resolve) val = resolve->val;

  return val;
}

/** Return the current value associated the key (first, second), or
 * NULL if no value is set.
 */

void *
fp_pair_map_get_by_digests(const fp_pair_map_t *map,
                           const char *first, const char *second)
{
  fp_pair_t k;

  tor_assert(first);
  tor_assert(second);

  memcpy(k.first, first, DIGEST_LEN);
  memcpy(k.second, second, DIGEST_LEN);

  return fp_pair_map_get(map, &k);
}

/** Remove the value currently associated with key from the map.
 * Return the value if one was set, or NULL if there was no entry for
 * key.  The caller must free any storage associated with the
 * returned value.
 */

void *
fp_pair_map_remove(fp_pair_map_t *map, const fp_pair_t *key)
{
  fp_pair_map_entry_t *resolve;
  fp_pair_map_entry_t search;
  void *val = NULL;

  tor_assert(map);
  tor_assert(key);

  memcpy(&(search.key), key, sizeof(*key));
  resolve = HT_REMOVE(fp_pair_map_impl, &(map->head), &search);
  if (resolve) {
    val = resolve->val;
    tor_free(resolve);
  }

  return val;
}

/** Remove all entries from map, and deallocate storage for those entries.
 * If free_val is provided, it is invoked on every value in map.
 */

void
fp_pair_map_free(fp_pair_map_t *map, void (*free_val)(void*))
{
  fp_pair_map_entry_t **ent, **next, *this;

  if (map) {
    for (ent = HT_START(fp_pair_map_impl, &(map->head));
         ent != NULL; ent = next) {
      this = *ent;
      next = HT_NEXT_RMV(fp_pair_map_impl, &(map->head), ent);
      if (free_val) free_val(this->val);
      tor_free(this);
    }
    tor_assert(HT_EMPTY(&(map->head)));
    HT_CLEAR(fp_pair_map_impl, &(map->head));
    tor_free(map);
  }
}

/** Return true iff map has no entries.
 */

int
fp_pair_map_isempty(const fp_pair_map_t *map)
{
  tor_assert(map);

  return HT_EMPTY(&(map->head));
}

/** Return the number of items in map.
 */

int
fp_pair_map_size(const fp_pair_map_t *map)
{
  tor_assert(map);

  return HT_SIZE(&(map->head));
}

/** return an iterator pointing to the start of map.
 */

fp_pair_map_iter_t *
fp_pair_map_iter_init(fp_pair_map_t *map)
{
  tor_assert(map);

  return HT_START(fp_pair_map_impl, &(map->head));
}

/** Advance iter a single step to the next entry of map, and return
 * its new value.
 */

fp_pair_map_iter_t *
fp_pair_map_iter_next(fp_pair_map_t *map, fp_pair_map_iter_t *iter)
{
  tor_assert(map);
  tor_assert(iter);

  return HT_NEXT(fp_pair_map_impl, &(map->head), iter);
}

/** Advance iter a single step to the next entry of map, removing the current
 * entry, and return its new value.
 */

fp_pair_map_iter_t *
fp_pair_map_iter_next_rmv(fp_pair_map_t *map, fp_pair_map_iter_t *iter)
{
  fp_pair_map_entry_t *rmv;

  tor_assert(map);
  tor_assert(iter);
  tor_assert(*iter);

  rmv = *iter;
  iter = HT_NEXT_RMV(fp_pair_map_impl, &(map->head), iter);
  tor_free(rmv);

  return iter;
}

/** Set *key_out and *val_out to the current entry pointed to by iter.
 */

void
fp_pair_map_iter_get(fp_pair_map_iter_t *iter,
                     fp_pair_t *key_out, void **val_out)
{
  tor_assert(iter);
  tor_assert(*iter);

  if (key_out) memcpy(key_out, &((*iter)->key), sizeof(fp_pair_t));
  if (val_out) *val_out = (*iter)->val;
}

/** Return true iff iter has advanced past the last entry of its map.
 */

int
fp_pair_map_iter_done(fp_pair_map_iter_t *iter)
{
  return (iter == NULL);
}

/** Assert if anything has gone wrong with the internal
 * representation of map.
 */

void
fp_pair_map_assert_ok(const fp_pair_map_t *map)
{
  tor_assert(!fp_pair_map_impl_HT_REP_IS_BAD_(&(map->head)));
}
Loading