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

📄 rendcommon.c

📁 关于tor匿名通信的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
  /* Lookup descriptor and return. */
  e = digestmap_get(rend_cache_v2_dir, desc_id_digest);
  if (e) {
    *desc = e->desc;
    return 1;
  }
  return 0;
}

/** Parse *desc, calculate its service id, and store it in the cache.
 * If we have a newer v0 descriptor with the same ID, ignore this one.
 * If we have an older descriptor with the same ID, replace it.
 * If we are acting as client due to the published flag and have any v2
 * descriptor with the same ID, reject this one in order to not get
 * confused with having both versions for the same service.
 * Return -1 if it's malformed or otherwise rejected; return 0 if
 * it's the same or older than one we've already got; return 1 if
 * it's novel. The published flag tells us if we store the descriptor
 * in our role as directory (1) or if we cache it as client (0).
 */
int
rend_cache_store(const char *desc, size_t desc_len, int published)
{
  rend_cache_entry_t *e;
  rend_service_descriptor_t *parsed;
  char query[REND_SERVICE_ID_LEN_BASE32+1];
  char key[REND_SERVICE_ID_LEN_BASE32+2]; /* 0<query>\0 */
  time_t now;
  or_options_t *options = get_options();
  tor_assert(rend_cache);
  parsed = rend_parse_service_descriptor(desc,desc_len);
  if (!parsed) {
    log_warn(LD_PROTOCOL,"Couldn't parse service descriptor.");
    return -1;
  }
  if (rend_get_service_id(parsed->pk, query)<0) {
    log_warn(LD_BUG,"Couldn't compute service ID.");
    rend_service_descriptor_free(parsed);
    return -1;
  }
  now = time(NULL);
  if (parsed->timestamp < now-REND_CACHE_MAX_AGE-REND_CACHE_MAX_SKEW) {
    log_fn(LOG_PROTOCOL_WARN, LD_REND,
           "Service descriptor %s is too old.", safe_str(query));
    rend_service_descriptor_free(parsed);
    return -1;
  }
  if (parsed->timestamp > now+REND_CACHE_MAX_SKEW) {
    log_fn(LOG_PROTOCOL_WARN, LD_REND,
           "Service descriptor %s is too far in the future.", safe_str(query));
    rend_service_descriptor_free(parsed);
    return -1;
  }
  /* Do we have a v2 descriptor and fetched this descriptor as a client? */
  tor_snprintf(key, sizeof(key), "2%s", query);
  if (!published && strmap_get_lc(rend_cache, key)) {
    log_info(LD_REND, "We already have a v2 descriptor for service %s.",
             safe_str(query));
    return -1;
  }
  /* report novel publication to statistics */
  if (published && options->HSAuthorityRecordStats) {
    hs_usage_note_publish_total(query, now);
  }
  tor_snprintf(key, sizeof(key), "0%s", query);
  e = (rend_cache_entry_t*) strmap_get_lc(rend_cache, key);
  if (e && e->parsed->timestamp > parsed->timestamp) {
    log_info(LD_REND,"We already have a newer service descriptor %s with the "
             "same ID and version.", safe_str(query));
    rend_service_descriptor_free(parsed);
    return 0;
  }
  if (e && e->len == desc_len && !memcmp(desc,e->desc,desc_len)) {
    log_info(LD_REND,"We already have this service descriptor %s.",
             safe_str(query));
    e->received = time(NULL);
    rend_service_descriptor_free(parsed);
    return 0;
  }
  if (!e) {
    e = tor_malloc_zero(sizeof(rend_cache_entry_t));
    strmap_set_lc(rend_cache, key, e);
    /* report novel publication to statistics */
    if (published && options->HSAuthorityRecordStats) {
      hs_usage_note_publish_novel(query, now);
    }
  } else {
    rend_service_descriptor_free(e->parsed);
    tor_free(e->desc);
  }
  e->received = time(NULL);
  e->parsed = parsed;
  e->len = desc_len;
  e->desc = tor_malloc(desc_len);
  memcpy(e->desc, desc, desc_len);

  log_debug(LD_REND,"Successfully stored rend desc '%s', len %d.",
            safe_str(query), (int)desc_len);
  return 1;
}

/** Parse the v2 service descriptor(s) in <b>desc</b> and store it/them to the
 * local rend cache. Don't attempt to decrypt the included list of introduction
 * points (as we don't have a descriptor cookie for it).
 *
 * If we have a newer descriptor with the same ID, ignore this one.
 * If we have an older descriptor with the same ID, replace it.
 * Return -2 if we are not acting as hidden service directory;
 * return -1 if the descriptor(s) were not parsable; return 0 if all
 * descriptors are the same or older than those we've already got;
 * return a positive number for the number of novel stored descriptors.
 */
int
rend_cache_store_v2_desc_as_dir(const char *desc)
{
  rend_service_descriptor_t *parsed;
  char desc_id[DIGEST_LEN];
  char *intro_content;
  size_t intro_size;
  size_t encoded_size;
  char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
  int number_parsed = 0, number_stored = 0;
  const char *current_desc = desc;
  const char *next_desc;
  rend_cache_entry_t *e;
  time_t now = time(NULL);
  tor_assert(rend_cache_v2_dir);
  tor_assert(desc);
  if (!hid_serv_acting_as_directory()) {
    /* Cannot store descs, because we are (currently) not acting as
     * hidden service directory. */
    log_info(LD_REND, "Cannot store descs: Not acting as hs dir");
    return -2;
  }
  while (rend_parse_v2_service_descriptor(&parsed, desc_id, &intro_content,
                                          &intro_size, &encoded_size,
                                          &next_desc, current_desc) >= 0) {
    number_parsed++;
    /* We don't care about the introduction points. */
    tor_free(intro_content);
    /* For pretty log statements. */
    base32_encode(desc_id_base32, sizeof(desc_id_base32),
                  desc_id, DIGEST_LEN);
    /* Is desc ID in the range that we are (directly or indirectly) responsible
     * for? */
    if (!hid_serv_responsible_for_desc_id(desc_id)) {
      log_info(LD_REND, "Service descriptor with desc ID %s is not in "
                        "interval that we are responsible for.",
               safe_str(desc_id_base32));
      goto skip;
    }
    /* Is descriptor too old? */
    if (parsed->timestamp < now - REND_CACHE_MAX_AGE-REND_CACHE_MAX_SKEW) {
      log_info(LD_REND, "Service descriptor with desc ID %s is too old.",
               safe_str(desc_id_base32));
      goto skip;
    }
    /* Is descriptor too far in the future? */
    if (parsed->timestamp > now + REND_CACHE_MAX_SKEW) {
      log_info(LD_REND, "Service descriptor with desc ID %s is too far in the "
                        "future.",
               safe_str(desc_id_base32));
      goto skip;
    }
    /* Do we already have a newer descriptor? */
    e = digestmap_get(rend_cache_v2_dir, desc_id);
    if (e && e->parsed->timestamp > parsed->timestamp) {
      log_info(LD_REND, "We already have a newer service descriptor with the "
                        "same desc ID %s and version.",
               safe_str(desc_id_base32));
      goto skip;
    }
    /* Do we already have this descriptor? */
    if (e && !strcmp(desc, e->desc)) {
      log_info(LD_REND, "We already have this service descriptor with desc "
                        "ID %s.", safe_str(desc_id_base32));
      e->received = time(NULL);
      goto skip;
    }
    /* Store received descriptor. */
    if (!e) {
      e = tor_malloc_zero(sizeof(rend_cache_entry_t));
      digestmap_set(rend_cache_v2_dir, desc_id, e);
    } else {
      rend_service_descriptor_free(e->parsed);
      tor_free(e->desc);
    }
    e->received = time(NULL);
    e->parsed = parsed;
    e->desc = tor_strndup(current_desc, encoded_size);
    e->len = encoded_size;
    log_info(LD_REND, "Successfully stored service descriptor with desc ID "
                      "'%s' and len %d.",
             safe_str(desc_id_base32), (int)encoded_size);
    number_stored++;
    goto advance;
  skip:
    rend_service_descriptor_free(parsed);
  advance:
    /* advance to next descriptor, if available. */
    current_desc = next_desc;
    /* check if there is a next descriptor. */
    if (!current_desc ||
        strcmpstart(current_desc, "rendezvous-service-descriptor "))
      break;
  }
  if (!number_parsed) {
    log_info(LD_REND, "Could not parse any descriptor.");
    return -1;
  }
  log_info(LD_REND, "Parsed %d and added %d descriptor%s.",
           number_parsed, number_stored, number_stored != 1 ? "s" : "");
  return number_stored;
}

/** Parse the v2 service descriptor in <b>desc</b>, decrypt the included list
 * of introduction points with <b>descriptor_cookie</b> (which may also be
 * <b>NULL</b> if decryption is not necessary), and store the descriptor to
 * the local cache under its version and service id.
 *
 * If we have a newer v2 descriptor with the same ID, ignore this one.
 * If we have an older descriptor with the same ID, replace it.
 * If we have any v0 descriptor with the same ID, reject this one in order
 * to not get confused with having both versions for the same service.
 * Return -2 if it's malformed or otherwise rejected; return -1 if we
 * already have a v0 descriptor here; return 0 if it's the same or older
 * than one we've already got; return 1 if it's novel.
 */
int
rend_cache_store_v2_desc_as_client(const char *desc,
                                   const char *descriptor_cookie)
{
  /*XXXX this seems to have a bit of duplicate code with
   * rend_cache_store_v2_desc_as_dir().  Fix that. */
  /* Though having similar elements, both functions were separated on
   * purpose:
   * - dirs don't care about encoded/encrypted introduction points, clients
   *   do.
   * - dirs store descriptors in a separate cache by descriptor ID, whereas
   *   clients store them by service ID; both caches are different data
   *   structures and have different access methods.
   * - dirs store a descriptor only if they are responsible for its ID,
   *   clients do so in every way (because they have requested it before).
   * - dirs can process multiple concatenated descriptors which is required
   *   for replication, whereas clients only accept a single descriptor.
   * Thus, combining both methods would result in a lot of if statements
   * which probably would not improve, but worsen code readability. -KL */
  rend_service_descriptor_t *parsed = NULL;
  char desc_id[DIGEST_LEN];
  char *intro_content = NULL;
  size_t intro_size;
  size_t encoded_size;
  const char *next_desc;
  time_t now = time(NULL);
  char key[REND_SERVICE_ID_LEN_BASE32+2];
  char service_id[REND_SERVICE_ID_LEN_BASE32+1];
  rend_cache_entry_t *e;
  tor_assert(rend_cache);
  tor_assert(desc);
  /* Parse the descriptor. */
  if (rend_parse_v2_service_descriptor(&parsed, desc_id, &intro_content,
                                       &intro_size, &encoded_size,
                                       &next_desc, desc) < 0) {
    if (parsed) rend_service_descriptor_free(parsed);
    tor_free(intro_content);
    log_warn(LD_REND, "Could not parse descriptor.");
    return -2;
  }
  /* Compute service ID from public key. */
  if (rend_get_service_id(parsed->pk, service_id)<0) {
    log_warn(LD_REND, "Couldn't compute service ID.");
    rend_service_descriptor_free(parsed);
    tor_free(intro_content);
    return -2;
  }
  /* Decode/decrypt introduction points. */
  if (intro_content) {
    if (rend_decrypt_introduction_points(parsed, descriptor_cookie,
                                         intro_content, intro_size) < 0) {
      log_warn(LD_PROTOCOL,"Couldn't decode/decrypt introduction points.");
      rend_service_descriptor_free(parsed);
      tor_free(intro_content);
      return -2;
    }
  } else {
    parsed->intro_nodes = smartlist_create();
  }
  /* We don't need the encoded/encrypted introduction points any longer. */
  tor_free(intro_content);
  /* Is descriptor too old? */
  if (parsed->timestamp < now - REND_CACHE_MAX_AGE-REND_CACHE_MAX_SKEW) {
    log_warn(LD_REND, "Service descriptor with service ID %s is too old.",
             safe_str(service_id));
    rend_service_descriptor_free(parsed);
    return -2;
  }
  /* Is descriptor too far in the future? */
  if (parsed->timestamp > now + REND_CACHE_MAX_SKEW) {
    log_warn(LD_REND, "Service descriptor with service ID %s is too far in "
                      "the future.", safe_str(service_id));
    rend_service_descriptor_free(parsed);
    return -2;
  }
  /* Do we have a v0 descriptor? */
  tor_snprintf(key, sizeof(key), "0%s", service_id);
  if (strmap_get_lc(rend_cache, key)) {
    log_info(LD_REND, "We already have a v0 descriptor for service ID %s.",
             safe_str(service_id));
    return -1;
  }
  /* Do we already have a newer descriptor? */
  tor_snprintf(key, sizeof(key), "2%s", service_id);
  e = (rend_cache_entry_t*) strmap_get_lc(rend_cache, key);
  if (e && e->parsed->timestamp > parsed->timestamp) {
    log_info(LD_REND, "We already have a newer service descriptor for "
                      "service ID %s with the same desc ID and version.",
             safe_str(service_id));
    rend_service_descriptor_free(parsed);
    return 0;
  }
  /* Do we already have this descriptor? */
  if (e && !strcmp(desc, e->desc)) {
    log_info(LD_REND,"We already have this service descriptor %s.",
             safe_str(service_id));
    e->received = time(NULL);
    rend_service_descriptor_free(parsed);
    return 0;
  }
  if (!e) {
    e = tor_malloc_zero(sizeof(rend_cache_entry_t));
    strmap_set_lc(rend_cache, key, e);
  } else {
    rend_service_descriptor_free(e->parsed);
    tor_free(e->desc);
  }
  e->received = time(NULL);
  e->parsed = parsed;
  e->desc = tor_malloc_zero(encoded_size + 1);
  strlcpy(e->desc, desc, encoded_size + 1);
  e->len = encoded_size;
  log_debug(LD_REND,"Successfully stored rend desc '%s', len %d.",
            safe_str(service_id), (int)encoded_size);
  return 1;
}

/** Called when we get a rendezvous-related relay cell on circuit
 * <b>circ</b>.  Dispatch on rendezvous relay command. */
void
rend_process_relay_cell(circuit_t *circ, int command, size_t length,
                        const char *payload)
{
  or_circuit_t *or_circ = NULL;
  origin_circuit_t *origin_circ = NULL;
  int r = -2;
  if (CIRCUIT_IS_ORIGIN(circ))
    origin_circ = TO_ORIGIN_CIRCUIT(circ);
  else
    or_circ = TO_OR_CIRCUIT(circ);

  switch (command) {
    case RELAY_COMMAND_ESTABLISH_INTRO:
      if (or_circ)
        r = rend_mid_establish_intro(or_circ,payload,length);
      break;
    case RELAY_COMMAND_ESTABLISH_RENDEZVOUS:
      if (or_circ)
        r = rend_mid_establish_rendezvous(or_circ,payload,length);
      break;
    case RELAY_COMMAND_INTRODUCE1:
      if (or_circ)
        r = rend_mid_introduce(or_circ,payload,length);
      break;
    case RELAY_COMMAND_INTRODUCE2:
      if (origin_circ)
        r = rend_service_introduce(origin_circ,payload,length);
      break;
    case RELAY_COMMAND_INTRODUCE_ACK:
      if (origin_circ)
        r = rend_client_introduction_acked(origin_circ,payload,length);
      break;
    case RELAY_COMMAND_RENDEZVOUS1:
      if (or_circ)
        r = rend_mid_rendezvous(or_circ,payload,length);
      break;
    case RELAY_COMMAND_RENDEZVOUS2:
      if (origin_circ)
        r = rend_client_receive_rendezvous(origin_circ,payload,length);
      break;
    case RELAY_COMMAND_INTRO_ESTABLISHED:
      if (origin_circ)
        r = rend_service_intro_established(origin_circ,payload,length);
      break;
    case RELAY_COMMAND_RENDEZVOUS_ESTABLISHED:
      if (origin_circ)
        r = rend_client_rendezvous_acked(origin_circ,payload,length);
      break;
    default:
      tor_fragile_assert();
  }

  if (r == -2)
    log_info(LD_PROTOCOL, "Dropping cell (type %d) for wrong circuit type.",
             command);
}

/** Return the number of entries in our rendezvous descriptor cache. */
int
rend_cache_size(void)
{
  return strmap_size(rend_cache);
}


⌨️ 快捷键说明

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