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

📄 circuituse.c

📁 关于tor匿名通信的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
   */
  int failed_at_last_hop = 0;
  /* If the last hop isn't open, and the second-to-last is, we failed
   * at the last hop. */
  if (circ->cpath &&
      circ->cpath->prev->state != CPATH_STATE_OPEN &&
      circ->cpath->prev->prev->state == CPATH_STATE_OPEN) {
    failed_at_last_hop = 1;
  }
  if (circ->cpath &&
      circ->cpath->state != CPATH_STATE_OPEN) {
    /* We failed at the first hop. If there's an OR connection
       to blame, blame it. */
    or_connection_t *n_conn = NULL;
    if (circ->_base.n_conn) {
      n_conn = circ->_base.n_conn;
    } else if (circ->_base.state == CIRCUIT_STATE_OR_WAIT) {
      /* we have to hunt for it */
      n_conn = connection_or_get_by_identity_digest(
                                               circ->_base.n_conn_id_digest);
    }
    if (n_conn) {
      log_info(LD_OR,
               "Our circuit failed to get a response from the first hop "
               "(%s:%d). I'm going to try to rotate to a better connection.",
               n_conn->_base.address, n_conn->_base.port);
      n_conn->_base.or_is_obsolete = 1;
      entry_guard_register_connect_status(n_conn->identity_digest, 0,
                                          time(NULL));
    }
    /* if there are any one-hop streams waiting on this circuit, fail
     * them now so they can retry elsewhere. */
    connection_ap_fail_onehop(circ->_base.n_conn_id_digest);
  }

  switch (circ->_base.purpose) {
    case CIRCUIT_PURPOSE_C_GENERAL:
      /* If we never built the circuit, note it as a failure. */
      circuit_increment_failure_count();
      if (failed_at_last_hop) {
        /* Make sure any streams that demand our last hop as their exit
         * know that it's unlikely to happen. */
        circuit_discard_optional_exit_enclaves(circ->cpath->prev->extend_info);
      }
      break;
    case CIRCUIT_PURPOSE_TESTING:
      circuit_testing_failed(circ, failed_at_last_hop);
      break;
    case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO:
      /* at Bob, waiting for introductions */
      if (circ->_base.state != CIRCUIT_STATE_OPEN) {
        circuit_increment_failure_count();
      }
      /* no need to care here, because bob will rebuild intro
       * points periodically. */
      break;
    case CIRCUIT_PURPOSE_C_INTRODUCING:
      /* at Alice, connecting to intro point */
      /* Don't increment failure count, since Bob may have picked
       * the introduction point maliciously */
      /* Alice will pick a new intro point when this one dies, if
       * the stream in question still cares. No need to act here. */
      break;
    case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
      /* at Alice, waiting for Bob */
      circuit_increment_failure_count();
      /* Alice will pick a new rend point when this one dies, if
       * the stream in question still cares. No need to act here. */
      break;
    case CIRCUIT_PURPOSE_S_CONNECT_REND:
      /* at Bob, connecting to rend point */
      /* Don't increment failure count, since Alice may have picked
       * the rendezvous point maliciously */
      log_info(LD_REND,
               "Couldn't connect to Alice's chosen rend point %s "
               "(%s hop failed).",
               escaped(build_state_get_exit_nickname(circ->build_state)),
               failed_at_last_hop?"last":"non-last");
      rend_service_relaunch_rendezvous(circ);
      break;
    /* default:
     * This won't happen in normal operation, but might happen if the
     * controller did it. Just let it slide. */
  }
}

/** Number of consecutive failures so far; should only be touched by
 * circuit_launch_new and circuit_*_failure_count.
 */
static int n_circuit_failures = 0;
/** Before the last time we called circuit_reset_failure_count(), were
 * there a lot of failures? */
static int did_circs_fail_last_period = 0;

/** Don't retry launching a new circuit if we try this many times with no
 * success. */
#define MAX_CIRCUIT_FAILURES 5

/** Launch a new circuit; see circuit_launch_by_extend_info() for
 * details on arguments. */
origin_circuit_t *
circuit_launch_by_router(uint8_t purpose,
                         routerinfo_t *exit, int flags)
{
  origin_circuit_t *circ;
  extend_info_t *info = NULL;
  if (exit)
    info = extend_info_from_router(exit);
  circ = circuit_launch_by_extend_info(purpose, info, flags);
  if (info)
    extend_info_free(info);
  return circ;
}

/** Launch a new circuit with purpose <b>purpose</b> and exit node
 * <b>extend_info</b> (or NULL to select a random exit node).  If flags
 * contains CIRCLAUNCH_NEED_UPTIME, choose among routers with high uptime.  If
 * CIRCLAUNCH_NEED_CAPACITY is set, choose among routers with high bandwidth.
 * If CIRCLAUNCH_IS_INTERNAL is true, the last hop need not be an exit node.
 * If CIRCLAUNCH_ONEHOP_TUNNEL is set, the circuit will have only one hop.
 * Return the newly allocated circuit on success, or NULL on failure. */
origin_circuit_t *
circuit_launch_by_extend_info(uint8_t purpose,
                              extend_info_t *extend_info,
                              int flags)
{
  origin_circuit_t *circ;
  int onehop_tunnel = flags & CIRCLAUNCH_ONEHOP_TUNNEL;

  if (!onehop_tunnel && !router_have_minimum_dir_info()) {
    log_debug(LD_CIRC,"Haven't fetched enough directory info yet; canceling "
              "circuit launch.");
    return NULL;
  }

  if ((extend_info || purpose != CIRCUIT_PURPOSE_C_GENERAL) &&
      purpose != CIRCUIT_PURPOSE_TESTING && !onehop_tunnel) {
    /* see if there are appropriate circs available to cannibalize. */
    /* XXX020 if we're planning to add a hop, perhaps we want to look for
     * internal circs rather than exit circs? -RD */
    circ = circuit_find_to_cannibalize(purpose, extend_info, flags);
    if (circ) {
      log_info(LD_CIRC,"Cannibalizing circ '%s' for purpose %d",
               build_state_get_exit_nickname(circ->build_state), purpose);
      circ->_base.purpose = purpose;
      /* reset the birth date of this circ, else expire_building
       * will see it and think it's been trying to build since it
       * began. */
      circ->_base.timestamp_created = time(NULL);
      switch (purpose) {
        case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
        case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO:
          /* it's ready right now */
          break;
        case CIRCUIT_PURPOSE_C_INTRODUCING:
        case CIRCUIT_PURPOSE_S_CONNECT_REND:
        case CIRCUIT_PURPOSE_C_GENERAL:
          /* need to add a new hop */
          tor_assert(extend_info);
          if (circuit_extend_to_new_exit(circ, extend_info) < 0)
            return NULL;
          break;
        default:
          log_warn(LD_BUG,
                   "unexpected purpose %d when cannibalizing a circ.",
                   purpose);
          tor_fragile_assert();
          return NULL;
      }
      return circ;
    }
  }

  if (did_circs_fail_last_period &&
      n_circuit_failures > MAX_CIRCUIT_FAILURES) {
    /* too many failed circs in a row. don't try. */
//    log_fn(LOG_INFO,"%d failures so far, not trying.",n_circuit_failures);
    return NULL;
  }

  /* try a circ. if it fails, circuit_mark_for_close will increment
   * n_circuit_failures */
  return circuit_establish_circuit(purpose, extend_info, flags);
}

/** Launch a new circuit; see circuit_launch_by_extend_info() for
 * details on arguments. */
origin_circuit_t *
circuit_launch_by_nickname(uint8_t purpose,
                           const char *exit_nickname, int flags)
{
  routerinfo_t *router = NULL;

  if (exit_nickname) {
    router = router_get_by_nickname(exit_nickname, 1);
    if (!router) {
      log_warn(LD_GENERAL, "Trying to launch circ by nickname, but "
               "no such OR as '%s'", exit_nickname);
      return NULL;
    }
  }
  return circuit_launch_by_router(purpose, router, flags);
}

/** Record another failure at opening a general circuit. When we have
 * too many, we'll stop trying for the remainder of this minute.
 */
static void
circuit_increment_failure_count(void)
{
  ++n_circuit_failures;
  log_debug(LD_CIRC,"n_circuit_failures now %d.",n_circuit_failures);
}

/** Reset the failure count for opening general circuits. This means
 * we will try MAX_CIRCUIT_FAILURES times more (if necessary) before
 * stopping again.
 */
void
circuit_reset_failure_count(int timeout)
{
  if (timeout && n_circuit_failures > MAX_CIRCUIT_FAILURES)
    did_circs_fail_last_period = 1;
  else
    did_circs_fail_last_period = 0;
  n_circuit_failures = 0;
}

/** Find an open circ that we're happy to use for <b>conn</b> and return 1. If
 * there isn't one, and there isn't one on the way, launch one and return
 * 0. If it will never work, return -1.
 *
 * Write the found or in-progress or launched circ into *circp.
 */
static int
circuit_get_open_circ_or_launch(edge_connection_t *conn,
                                uint8_t desired_circuit_purpose,
                                origin_circuit_t **circp)
{
  origin_circuit_t *circ;
  int check_exit_policy;
  int need_uptime, need_internal;
  int want_onehop;
  or_options_t *options = get_options();

  tor_assert(conn);
  tor_assert(circp);
  tor_assert(conn->_base.state == AP_CONN_STATE_CIRCUIT_WAIT);
  check_exit_policy =
      conn->socks_request->command == SOCKS_COMMAND_CONNECT &&
      !conn->use_begindir &&
      !connection_edge_is_rendezvous_stream(conn);
  want_onehop = conn->want_onehop;

  need_uptime = !conn->want_onehop && !conn->use_begindir &&
                smartlist_string_num_isin(options->LongLivedPorts,
                                          conn->socks_request->port);
  need_internal = desired_circuit_purpose != CIRCUIT_PURPOSE_C_GENERAL;

  circ = circuit_get_best(conn, 1, desired_circuit_purpose,
                          need_uptime, need_internal);

  if (circ) {
    *circp = circ;
    return 1; /* we're happy */
  }

  if (!want_onehop && !router_have_minimum_dir_info()) {
    if (!connection_get_by_type(CONN_TYPE_DIR)) {
      if (options->UseBridges && bridges_known_but_down()) {
        log_notice(LD_APP|LD_DIR,
                   "Application request when we're believed to be "
                   "offline. Optimistically trying known bridges again.");
        bridges_retry_all();
      } else if (!options->UseBridges || any_bridge_descriptors_known()) {
        log_notice(LD_APP|LD_DIR,
                   "Application request when we're believed to be "
                   "offline. Optimistically trying directory fetches again.");
        routerlist_retry_directory_downloads(time(NULL));
      }
    }
    /* the stream will be dealt with when router_have_minimum_dir_info becomes
     * 1, or when all directory attempts fail and directory_all_unreachable()
     * kills it.
     */
    return 0;
  }

  /* Do we need to check exit policy? */
  if (check_exit_policy) {
    struct in_addr in;
    uint32_t addr = 0;
    if (tor_inet_aton(conn->socks_request->address, &in))
      addr = ntohl(in.s_addr);
    if (router_exit_policy_all_routers_reject(addr, conn->socks_request->port,
                                              need_uptime)) {
      log_notice(LD_APP,
                 "No Tor server exists that allows exit to %s:%d. Rejecting.",
                 safe_str(conn->socks_request->address),
                 conn->socks_request->port);
      return -1;
    }
  }

  /* is one already on the way? */
  circ = circuit_get_best(conn, 0, desired_circuit_purpose,
                          need_uptime, need_internal);
  if (circ)
    log_debug(LD_CIRC, "one on the way!");
  if (!circ) {
    extend_info_t *extend_info=NULL;
    uint8_t new_circ_purpose;

    if (desired_circuit_purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) {
      /* need to pick an intro point */
      extend_info = rend_client_get_random_intro(conn->rend_query);
      if (!extend_info) {
        log_info(LD_REND,
                 "No intro points for '%s': refetching service descriptor.",
                 safe_str(conn->rend_query));
        rend_client_refetch_renddesc(conn->rend_query);
        rend_client_refetch_v2_renddesc(conn->rend_query);
        conn->_base.state = AP_CONN_STATE_RENDDESC_WAIT;
        return 0;
      }
      log_info(LD_REND,"Chose '%s' as intro point for '%s'.",
               extend_info->nickname, safe_str(conn->rend_query));
    }

    /* If we have specified a particular exit node for our
     * connection, then be sure to open a circuit to that exit node.
     */
    if (desired_circuit_purpose == CIRCUIT_PURPOSE_C_GENERAL) {
      if (conn->chosen_exit_name) {
        routerinfo_t *r;
        int opt = conn->_base.chosen_exit_optional;
        r = router_get_by_nickname(conn->chosen_exit_name, 1);
        if (r) {
          extend_info = extend_info_from_router(r);
        } else {
          log_debug(LD_DIR, "considering %d, %s",
                    want_onehop, conn->chosen_exit_name);
          if (want_onehop && conn->chosen_exit_name[0] == '$') {
            /* We're asking for a one-hop circuit to a router that
             * we don't have a routerinfo about. Make up an extend_info. */
            char digest[DIGEST_LEN];
            char *hexdigest = conn->chosen_exit_name+1;
            struct in_addr in;
            if (strlen(hexdigest) < HEX_DIGEST_LEN ||
                base16_decode(digest,DIGEST_LEN,hexdigest,HEX_DIGEST_LEN)<0) {
              log_info(LD_DIR, "Broken exit digest on tunnel conn. Closing.");
              return -1;
            }
            if (!tor_inet_aton(conn->socks_request->address, &in)) {
              log_info(LD_DIR, "Broken address on tunnel conn. Closing.");
              return -1;
            }
            extend_info = extend_info_alloc(conn->chosen_exit_name+1,
                                            digest, NULL, ntohl(in.s_addr),

⌨️ 快捷键说明

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