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

📄 rendcommon.c

📁 关于tor匿名通信的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
    written = result;
    /* Add introduction points. */
    if (ipos_base64) {
      result = tor_snprintf(desc_str + written, desc_len - written,
                            "introduction-points\n"
                            "-----BEGIN MESSAGE-----\n%s"
                            "-----END MESSAGE-----\n",
                            ipos_base64);
      if (result < 0) {
        log_warn(LD_BUG, "could not write introduction points.");
        rend_encoded_v2_service_descriptor_free(enc);
        goto err;
      }
      written += result;
    }
    /* Add signature. */
    strlcpy(desc_str + written, "signature\n", desc_len - written);
    written += strlen(desc_str + written);
    if (crypto_digest(desc_digest, desc_str, written) < 0) {
      log_warn(LD_BUG, "could not create digest.");
      rend_encoded_v2_service_descriptor_free(enc);
      goto err;
    }
    if (router_append_dirobj_signature(desc_str + written,
                                       desc_len - written,
                                       desc_digest, desc->pk) < 0) {
      log_warn(LD_BUG, "Couldn't sign desc.");
      rend_encoded_v2_service_descriptor_free(enc);
      goto err;
    }
    written += strlen(desc_str+written);
    if (written+2 > desc_len) {
        log_warn(LD_BUG, "Could not finish desc.");
        rend_encoded_v2_service_descriptor_free(enc);
        goto err;
    }
    desc_str[written++] = '\n';
    desc_str[written++] = 0;
    /* Check if we can parse our own descriptor. */
    if (!rend_desc_v2_is_parsable(enc)) {
      log_warn(LD_BUG, "Could not parse my own descriptor: %s", desc_str);
      rend_encoded_v2_service_descriptor_free(enc);
      goto err;
    }
    smartlist_add(descs_out, enc);
  }

  log_info(LD_REND, "Successfully encoded a v2 descriptor and "
                    "confirmed that it is parsable.");
  goto done;

 err:
  SMARTLIST_FOREACH(descs_out, rend_encoded_v2_service_descriptor_t *, d,
                    rend_encoded_v2_service_descriptor_free(d););
  smartlist_clear(descs_out);
  seconds_valid = -1;

 done:
  tor_free(ipos_base64);
  return seconds_valid;
}

/** Encode a service descriptor for <b>desc</b>, and sign it with
 * <b>key</b>. Store the descriptor in *<b>str_out</b>, and set
 * *<b>len_out</b> to its length.
 */
int
rend_encode_service_descriptor(rend_service_descriptor_t *desc,
                               crypto_pk_env_t *key,
                               char **str_out, size_t *len_out)
{
  char *cp;
  char *end;
  int i, r;
  size_t asn1len;
  size_t buflen =
         PK_BYTES*2*(smartlist_len(desc->intro_nodes)+2);/*Too long, but ok*/
  cp = *str_out = tor_malloc(buflen);
  end = cp + PK_BYTES*2*(smartlist_len(desc->intro_nodes)+1);
  r = crypto_pk_asn1_encode(desc->pk, cp+2, end-(cp+2));
  if (r < 0) {
    tor_free(*str_out);
    return -1;
  }
  asn1len = r;
  set_uint16(cp, htons((uint16_t)asn1len));
  cp += 2+asn1len;
  set_uint32(cp, htonl((uint32_t)desc->timestamp));
  cp += 4;
  set_uint16(cp, htons((uint16_t)smartlist_len(desc->intro_nodes)));
  cp += 2;
  for (i=0; i < smartlist_len(desc->intro_nodes); ++i) {
    rend_intro_point_t *intro = smartlist_get(desc->intro_nodes, i);
    char ipoint[HEX_DIGEST_LEN+2];
    ipoint[0] = '$';
    base16_encode(ipoint+1, HEX_DIGEST_LEN+1,
                  intro->extend_info->identity_digest,
                  DIGEST_LEN);
    tor_assert(buflen + *str_out >= cp); /* XXX021 This assert is a kludge. */
    strlcpy(cp, ipoint, buflen-(cp-*str_out));
    cp += strlen(ipoint)+1;
  }
  note_crypto_pk_op(REND_SERVER);
  r = crypto_pk_private_sign_digest(key, cp, *str_out, cp-*str_out);
  if (r<0) {
    tor_free(*str_out);
    return -1;
  }
  cp += r;
  *len_out = (size_t)(cp-*str_out);
  return 0;
}

/** Parse a service descriptor at <b>str</b> (<b>len</b> bytes).  On
 * success, return a newly alloced service_descriptor_t.  On failure,
 * return NULL.
 */
rend_service_descriptor_t *
rend_parse_service_descriptor(const char *str, size_t len)
{
  rend_service_descriptor_t *result = NULL;
  int i, n_intro_points;
  size_t keylen, asn1len;
  const char *end, *cp, *eos;
  rend_intro_point_t *intro;

  result = tor_malloc_zero(sizeof(rend_service_descriptor_t));
  cp = str;
  end = str+len;
  if (end-cp<2) goto truncated;
  result->version = 0;
  if (end-cp < 2) goto truncated;
  asn1len = ntohs(get_uint16(cp));
  cp += 2;
  if ((size_t)(end-cp) < asn1len) goto truncated;
  result->pk = crypto_pk_asn1_decode(cp, asn1len);
  if (!result->pk) goto truncated;
  cp += asn1len;
  if (end-cp < 4) goto truncated;
  result->timestamp = (time_t) ntohl(get_uint32(cp));
  cp += 4;
  result->protocols = 1<<2; /* always use intro format 2 */
  if (end-cp < 2) goto truncated;
  n_intro_points = ntohs(get_uint16(cp));
  cp += 2;

  result->intro_nodes = smartlist_create();
  for (i=0;i<n_intro_points;++i) {
    if (end-cp < 2) goto truncated;
    eos = (const char *)memchr(cp,'\0',end-cp);
    if (!eos) goto truncated;
    /* Write nickname to extend info, but postpone the lookup whether
     * we know that router. It's not part of the parsing process. */
    intro = tor_malloc_zero(sizeof(rend_intro_point_t));
    intro->extend_info = tor_malloc_zero(sizeof(extend_info_t));
    strlcpy(intro->extend_info->nickname, cp,
            sizeof(intro->extend_info->nickname));
    smartlist_add(result->intro_nodes, intro);
    cp = eos+1;
  }
  keylen = crypto_pk_keysize(result->pk);
  tor_assert(end-cp >= 0);
  if ((size_t)(end-cp) < keylen) goto truncated;
  if ((size_t)(end-cp) > keylen) {
    log_warn(LD_PROTOCOL,
             "Signature is %d bytes too long on service descriptor.",
             (int)((size_t)(end-cp) - keylen));
    goto error;
  }
  note_crypto_pk_op(REND_CLIENT);
  if (crypto_pk_public_checksig_digest(result->pk,
                                       (char*)str,cp-str, /* data */
                                       (char*)cp,end-cp  /* signature*/
                                       )<0) {
    log_warn(LD_PROTOCOL, "Bad signature on service descriptor.");
    goto error;
  }

  return result;
 truncated:
  log_warn(LD_PROTOCOL, "Truncated service descriptor.");
 error:
  rend_service_descriptor_free(result);
  return NULL;
}

/** Sets <b>out</b> to the first 10 bytes of the digest of <b>pk</b>,
 * base32 encoded.  NUL-terminates out.  (We use this string to
 * identify services in directory requests and .onion URLs.)
 */
int
rend_get_service_id(crypto_pk_env_t *pk, char *out)
{
  char buf[DIGEST_LEN];
  tor_assert(pk);
  if (crypto_pk_get_digest(pk, buf) < 0)
    return -1;
  base32_encode(out, REND_SERVICE_ID_LEN_BASE32+1, buf, REND_SERVICE_ID_LEN);
  return 0;
}

/* ==== Rendezvous service descriptor cache. */

/** How old do we let hidden service descriptors get before discarding
 * them as too old? */
#define REND_CACHE_MAX_AGE (2*24*60*60)
/** How wrong do we assume our clock may be when checking whether hidden
 * services are too old or too new? */
#define REND_CACHE_MAX_SKEW (24*60*60)

/** Map from service id (as generated by rend_get_service_id) to
 * rend_cache_entry_t. */
static strmap_t *rend_cache = NULL;

/** Map from descriptor id to rend_cache_entry_t; only for hidden service
 * directories. */
static digestmap_t *rend_cache_v2_dir = NULL;

/** Initializes the service descriptor cache.
 */
void
rend_cache_init(void)
{
  rend_cache = strmap_new();
  rend_cache_v2_dir = digestmap_new();
}

/** Helper: free storage held by a single service descriptor cache entry. */
static void
_rend_cache_entry_free(void *p)
{
  rend_cache_entry_t *e = p;
  rend_service_descriptor_free(e->parsed);
  tor_free(e->desc);
  tor_free(e);
}

/** Free all storage held by the service descriptor cache. */
void
rend_cache_free_all(void)
{
  strmap_free(rend_cache, _rend_cache_entry_free);
  digestmap_free(rend_cache_v2_dir, _rend_cache_entry_free);
  rend_cache = NULL;
  rend_cache_v2_dir = NULL;
}

/** Removes all old entries from the service descriptor cache.
 */
void
rend_cache_clean(void)
{
  strmap_iter_t *iter;
  const char *key;
  void *val;
  rend_cache_entry_t *ent;
  time_t cutoff;
  cutoff = time(NULL) - REND_CACHE_MAX_AGE - REND_CACHE_MAX_SKEW;
  for (iter = strmap_iter_init(rend_cache); !strmap_iter_done(iter); ) {
    strmap_iter_get(iter, &key, &val);
    ent = (rend_cache_entry_t*)val;
    if (ent->parsed->timestamp < cutoff) {
      iter = strmap_iter_next_rmv(rend_cache, iter);
      _rend_cache_entry_free(ent);
    } else {
      iter = strmap_iter_next(rend_cache, iter);
    }
  }
}

/** Remove all old v2 descriptors and those for which this hidden service
 * directory is not responsible for any more. */
void
rend_cache_clean_v2_descs_as_dir(void)
{
  digestmap_iter_t *iter;
  time_t cutoff = time(NULL) - REND_CACHE_MAX_AGE - REND_CACHE_MAX_SKEW;
  for (iter = digestmap_iter_init(rend_cache_v2_dir);
       !digestmap_iter_done(iter); ) {
    const char *key;
    void *val;
    rend_cache_entry_t *ent;
    digestmap_iter_get(iter, &key, &val);
    ent = val;
    if (ent->parsed->timestamp < cutoff ||
        !hid_serv_responsible_for_desc_id(key)) {
      char key_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
      base32_encode(key_base32, sizeof(key_base32), key, DIGEST_LEN);
      log_info(LD_REND, "Removing descriptor with ID '%s' from cache",
               safe_str(key_base32));
      iter = digestmap_iter_next_rmv(rend_cache_v2_dir, iter);
      _rend_cache_entry_free(ent);
    } else {
      iter = digestmap_iter_next(rend_cache_v2_dir, iter);
    }
  }
}

/** Determines whether <b>a</b> is in the interval of <b>b</b> (excluded) and
 * <b>c</b> (included) in a circular digest ring; returns 1 if this is the
 * case, and 0 otherwise.
 */
int
rend_id_is_in_interval(const char *a, const char *b, const char *c)
{
  int a_b, b_c, c_a;
  tor_assert(a);
  tor_assert(b);
  tor_assert(c);

  /* There are five cases in which a is outside the interval ]b,c]: */
  a_b = memcmp(a,b,DIGEST_LEN);
  if (a_b == 0)
    return 0; /* 1. a == b (b is excluded) */
  b_c = memcmp(b,c,DIGEST_LEN);
  if (b_c == 0)
    return 0; /* 2. b == c (interval is empty) */
  else if (a_b <= 0 && b_c < 0)
    return 0; /* 3. a b c */
  c_a = memcmp(c,a,DIGEST_LEN);
  if (c_a < 0 && a_b <= 0)
    return 0; /* 4. c a b */
  else if (b_c < 0 && c_a < 0)
    return 0; /* 5. b c a */

  /* In the other cases (a c b; b a c; c b a), a is inside the interval. */
  return 1;
}

/** Return true iff <b>query</b> is a syntactically valid service ID (as
 * generated by rend_get_service_id).  */
int
rend_valid_service_id(const char *query)
{
  if (strlen(query) != REND_SERVICE_ID_LEN_BASE32)
    return 0;

  if (strspn(query, BASE32_CHARS) != REND_SERVICE_ID_LEN_BASE32)
    return 0;

  return 1;
}

/** If we have a cached rend_cache_entry_t for the service ID <b>query</b>
 * with <b>version</b>, set *<b>e</b> to that entry and return 1.
 * Else return 0. If <b>version</b> is nonnegative, only return an entry
 * in that descriptor format version. Otherwise (if <b>version</b> is
 * negative), return the most recent format we have.
 */
int
rend_cache_lookup_entry(const char *query, int version, rend_cache_entry_t **e)
{
  char key[REND_SERVICE_ID_LEN_BASE32+2]; /* <version><query>\0 */
  tor_assert(rend_cache);
  if (!rend_valid_service_id(query))
    return -1;
  *e = NULL;
  if (version != 0) {
    tor_snprintf(key, sizeof(key), "2%s", query);
    *e = strmap_get_lc(rend_cache, key);
  }
  if (!*e && version != 2) {
    tor_snprintf(key, sizeof(key), "0%s", query);
    *e = strmap_get_lc(rend_cache, key);
  }
  if (!*e)
    return 0;
  return 1;
}

/** <b>query</b> is a base-32'ed service id. If it's malformed, return -1.
 * Else look it up.
 *   - If it is found, point *desc to it, and write its length into
 *     *desc_len, and return 1.
 *   - If it is not found, return 0.
 * Note: calls to rend_cache_clean or rend_cache_store may invalidate
 * *desc.
 */
int
rend_cache_lookup_desc(const char *query, int version, const char **desc,
                       size_t *desc_len)
{
  rend_cache_entry_t *e;
  int r;
  r = rend_cache_lookup_entry(query,version,&e);
  if (r <= 0) return r;
  *desc = e->desc;
  *desc_len = e->len;
  return 1;
}

/** Lookup the v2 service descriptor with base32-encoded <b>desc_id</b> and
 * copy the pointer to it to *<b>desc</b>.  Return 1 on success, 0 on
 * well-formed-but-not-found, and -1 on failure.
 */
int
rend_cache_lookup_v2_desc_as_dir(const char *desc_id, const char **desc)
{
  rend_cache_entry_t *e;
  char desc_id_digest[DIGEST_LEN];
  tor_assert(rend_cache_v2_dir);
  if (base32_decode(desc_id_digest, DIGEST_LEN,
                    desc_id, REND_DESC_ID_V2_LEN_BASE32) < 0) {
    log_warn(LD_REND, "Descriptor ID contains illegal characters: %s",
             safe_str(desc_id));
    return -1;
  }
  /* Determine if we are responsible. */
  if (hid_serv_responsible_for_desc_id(desc_id_digest) < 0) {
    log_info(LD_REND, "Could not answer fetch request for v2 descriptor; "
                      "either we are no hidden service directory, or we are "
                      "not responsible for the requested ID.");
    return -1;
  }

⌨️ 快捷键说明

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