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

📄 connection_edge.c

📁 关于tor匿名通信的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:

  SMARTLIST_FOREACH(conns, connection_t *, c,
  {
    if (c->type != CONN_TYPE_AP)
      continue;
    conn = TO_EDGE_CONN(c);
    /* if it's an internal linked connection, don't yell its status. */
    severity = (!conn->_base.addr && !conn->_base.port)
      ? LOG_INFO : LOG_NOTICE;
    seconds_idle = (int)( now - conn->_base.timestamp_lastread );

    if (AP_CONN_STATE_IS_UNATTACHED(conn->_base.state)) {
      if (seconds_idle >= options->SocksTimeout) {
        log_fn(severity, LD_APP,
            "Tried for %d seconds to get a connection to %s:%d. "
            "Giving up. (%s)",
            seconds_idle, safe_str(conn->socks_request->address),
            conn->socks_request->port,
            conn_state_to_string(CONN_TYPE_AP, conn->_base.state));
        connection_mark_unattached_ap(conn, END_STREAM_REASON_TIMEOUT);
      }
      continue;
    }

    if (conn->_base.state == AP_CONN_STATE_OPEN)
      continue;

    /* We're in state connect_wait or resolve_wait now -- waiting for a
     * reply to our relay cell. See if we want to retry/give up. */

    cutoff = compute_retry_timeout(conn);
    if (seconds_idle < cutoff)
      continue;
    circ = circuit_get_by_edge_conn(conn);
    if (!circ) { /* it's vanished? */
      log_info(LD_APP,"Conn is waiting (address %s), but lost its circ.",
               safe_str(conn->socks_request->address));
      connection_mark_unattached_ap(conn, END_STREAM_REASON_TIMEOUT);
      continue;
    }
    if (circ->purpose == CIRCUIT_PURPOSE_C_REND_JOINED) {
      if (seconds_idle >= options->SocksTimeout) {
        log_fn(severity, LD_REND,
               "Rend stream is %d seconds late. Giving up on address"
               " '%s.onion'.",
               seconds_idle,
               safe_str(conn->socks_request->address));
        connection_edge_end(conn, END_STREAM_REASON_TIMEOUT);
        connection_mark_unattached_ap(conn, END_STREAM_REASON_TIMEOUT);
      }
      continue;
    }
    tor_assert(circ->purpose == CIRCUIT_PURPOSE_C_GENERAL);
    log_fn(cutoff < 15 ? LOG_INFO : severity, LD_APP,
           "We tried for %d seconds to connect to '%s' using exit '%s'."
           " Retrying on a new circuit.",
           seconds_idle, safe_str(conn->socks_request->address),
           conn->cpath_layer ?
             conn->cpath_layer->extend_info->nickname : "*unnamed*");
    /* send an end down the circuit */
    connection_edge_end(conn, END_STREAM_REASON_TIMEOUT);
    /* un-mark it as ending, since we're going to reuse it */
    conn->_base.edge_has_sent_end = 0;
    conn->end_reason = 0;
    /* kludge to make us not try this circuit again, yet to allow
     * current streams on it to survive if they can: make it
     * unattractive to use for new streams */
    tor_assert(circ->timestamp_dirty);
    circ->timestamp_dirty -= options->MaxCircuitDirtiness;
    /* give our stream another 'cutoff' seconds to try */
    conn->_base.timestamp_lastread += cutoff;
    if (conn->num_socks_retries < 250) /* avoid overflow */
      conn->num_socks_retries++;
    /* move it back into 'pending' state, and try to attach. */
    if (connection_ap_detach_retriable(conn, TO_ORIGIN_CIRCUIT(circ),
                                       END_STREAM_REASON_TIMEOUT)<0) {
      if (!conn->_base.marked_for_close)
        connection_mark_unattached_ap(conn, END_STREAM_REASON_CANT_ATTACH);
    }
  }); /* end foreach */
}

/** Tell any AP streams that are waiting for a new circuit to try again,
 * either attaching to an available circ or launching a new one.
 */
void
connection_ap_attach_pending(void)
{
  edge_connection_t *edge_conn;
  smartlist_t *conns = get_connection_array();
  SMARTLIST_FOREACH(conns, connection_t *, conn,
  {
    if (conn->marked_for_close ||
        conn->type != CONN_TYPE_AP ||
        conn->state != AP_CONN_STATE_CIRCUIT_WAIT)
      continue;
    edge_conn = TO_EDGE_CONN(conn);
    if (connection_ap_handshake_attach_circuit(edge_conn) < 0) {
      if (!edge_conn->_base.marked_for_close)
        connection_mark_unattached_ap(edge_conn,
                                      END_STREAM_REASON_CANT_ATTACH);
    }
  });
}

/** Tell any AP streams that are waiting for a onehop tunnel to
 * <b>failed_digest</b> that they are going to fail. */
/* XXX021 We should get rid of this function, and instead attach
 * onehop streams to circ->p_streams so they get marked in
 * circuit_mark_for_close like normal p_streams. */
void
connection_ap_fail_onehop(const char *failed_digest)
{
  edge_connection_t *edge_conn;
  char digest[DIGEST_LEN];
  smartlist_t *conns = get_connection_array();
  SMARTLIST_FOREACH(conns, connection_t *, conn,
  {
    if (conn->marked_for_close ||
        conn->type != CONN_TYPE_AP ||
        conn->state != AP_CONN_STATE_CIRCUIT_WAIT)
      continue;
    edge_conn = TO_EDGE_CONN(conn);
    if (!edge_conn->want_onehop)
      continue;
    if (!hexdigest_to_digest(edge_conn->chosen_exit_name, digest) &&
        !memcmp(digest, failed_digest, DIGEST_LEN)) {
      log_info(LD_APP, "Closing onehop stream to '%s' because the OR conn "
                       "just failed.", edge_conn->chosen_exit_name);
      connection_mark_unattached_ap(edge_conn, END_STREAM_REASON_TIMEOUT);
    }
  });
}

/** A circuit failed to finish on its last hop <b>info</b>. If there
 * are any streams waiting with this exit node in mind, but they
 * don't absolutely require it, make them give up on it.
 */
void
circuit_discard_optional_exit_enclaves(extend_info_t *info)
{
  edge_connection_t *edge_conn;
  routerinfo_t *r1, *r2;

  smartlist_t *conns = get_connection_array();
  SMARTLIST_FOREACH(conns, connection_t *, conn,
  {
    if (conn->marked_for_close ||
        conn->type != CONN_TYPE_AP ||
        conn->state != AP_CONN_STATE_CIRCUIT_WAIT ||
        (!conn->chosen_exit_optional &&
         !conn->chosen_exit_retries))
      continue;
    edge_conn = TO_EDGE_CONN(conn);
    r1 = router_get_by_nickname(edge_conn->chosen_exit_name, 0);
    r2 = router_get_by_nickname(info->nickname, 0);
    if (!r1 || !r2 || r1 != r2)
      continue;
    tor_assert(edge_conn->socks_request);
    if (conn->chosen_exit_optional) {
      log_info(LD_APP, "Giving up on enclave exit '%s' for destination %s.",
               safe_str(edge_conn->chosen_exit_name),
               escaped_safe_str(edge_conn->socks_request->address));
      conn->chosen_exit_optional = 0;
      tor_free(edge_conn->chosen_exit_name); /* clears it */
      /* if this port is dangerous, warn or reject it now that we don't
       * think it'll be using an enclave. */
      consider_plaintext_ports(edge_conn, edge_conn->socks_request->port);
    }
    if (conn->chosen_exit_retries) {
      if (--conn->chosen_exit_retries == 0) { /* give up! */
        clear_trackexithost_mappings(edge_conn->chosen_exit_name);
        tor_free(edge_conn->chosen_exit_name); /* clears it */
        /* if this port is dangerous, warn or reject it now that we don't
         * think it'll be using an enclave. */
        consider_plaintext_ports(edge_conn, edge_conn->socks_request->port);
      }
    }
  });
}

/** The AP connection <b>conn</b> has just failed while attaching or
 * sending a BEGIN or resolving on <b>circ</b>, but another circuit
 * might work. Detach the circuit, and either reattach it, launch a
 * new circuit, tell the controller, or give up as a appropriate.
 *
 * Returns -1 on err, 1 on success, 0 on not-yet-sure.
 */
int
connection_ap_detach_retriable(edge_connection_t *conn, origin_circuit_t *circ,
                               int reason)
{
  control_event_stream_status(conn, STREAM_EVENT_FAILED_RETRIABLE, reason);
  conn->_base.timestamp_lastread = time(NULL);
  if (! get_options()->LeaveStreamsUnattached) {
    conn->_base.state = AP_CONN_STATE_CIRCUIT_WAIT;
    circuit_detach_stream(TO_CIRCUIT(circ),conn);
    return connection_ap_handshake_attach_circuit(conn);
  } else {
    conn->_base.state = AP_CONN_STATE_CONTROLLER_WAIT;
    circuit_detach_stream(TO_CIRCUIT(circ),conn);
    return 0;
  }
}

/** A client-side struct to remember requests to rewrite addresses
 * to new addresses. These structs are stored in the hash table
 * "addressmap" below.
 *
 * There are 5 ways to set an address mapping:
 * - A MapAddress command from the controller [permanent]
 * - An AddressMap directive in the torrc [permanent]
 * - When a TrackHostExits torrc directive is triggered [temporary]
 * - When a dns resolve succeeds [temporary]
 * - When a dns resolve fails [temporary]
 *
 * When an addressmap request is made but one is already registered,
 * the new one is replaced only if the currently registered one has
 * no "new_address" (that is, it's in the process of dns resolve),
 * or if the new one is permanent (expires==0 or 1).
 *
 * (We overload the 'expires' field, using "0" for mappings set via
 * the configuration file, "1" for mappings set from the control
 * interface, and other values for DNS mappings that can expire.)
 */
typedef struct {
  char *new_address;
  time_t expires;
  addressmap_entry_source_t source:3;
  short num_resolve_failures;
} addressmap_entry_t;

/** Entry for mapping addresses to which virtual address we mapped them to. */
typedef struct {
  char *ipv4_address;
  char *hostname_address;
} virtaddress_entry_t;

/** A hash table to store client-side address rewrite instructions. */
static strmap_t *addressmap=NULL;
/**
 * Table mapping addresses to which virtual address, if any, we
 * assigned them to.
 *
 * We maintain the following invariant: if [A,B] is in
 * virtaddress_reversemap, then B must be a virtual address, and [A,B]
 * must be in addressmap.  We do not require that the converse hold:
 * if it fails, then we could end up mapping two virtual addresses to
 * the same address, which is no disaster.
 **/
static strmap_t *virtaddress_reversemap=NULL;

/** Initialize addressmap. */
void
addressmap_init(void)
{
  addressmap = strmap_new();
  virtaddress_reversemap = strmap_new();
}

/** Free the memory associated with the addressmap entry <b>_ent</b>. */
static void
addressmap_ent_free(void *_ent)
{
  addressmap_entry_t *ent = _ent;
  tor_free(ent->new_address);
  tor_free(ent);
}

/** Free storage held by a virtaddress_entry_t* entry in <b>ent</b>. */
static void
addressmap_virtaddress_ent_free(void *_ent)
{
  virtaddress_entry_t *ent = _ent;
  tor_free(ent->ipv4_address);
  tor_free(ent->hostname_address);
  tor_free(ent);
}

/** Free storage held by a virtaddress_entry_t* entry in <b>ent</b>. */
static void
addressmap_virtaddress_remove(const char *address, addressmap_entry_t *ent)
{
  if (ent && ent->new_address &&
      address_is_in_virtual_range(ent->new_address)) {
    virtaddress_entry_t *ve =
      strmap_get(virtaddress_reversemap, ent->new_address);
    /*log_fn(LOG_NOTICE,"remove reverse mapping for %s",ent->new_address);*/
    if (ve) {
      if (!strcmp(address, ve->ipv4_address))
        tor_free(ve->ipv4_address);
      if (!strcmp(address, ve->hostname_address))
        tor_free(ve->hostname_address);
      if (!ve->ipv4_address && !ve->hostname_address) {
        tor_free(ve);
        strmap_remove(virtaddress_reversemap, ent->new_address);
      }
    }
  }
}

/** Remove <b>ent</b> (which must be mapped to by <b>address</b>) from the
 * client address maps. */
static void
addressmap_ent_remove(const char *address, addressmap_entry_t *ent)
{
  addressmap_virtaddress_remove(address, ent);
  addressmap_ent_free(ent);
}

/** Unregister all TrackHostExits mappings from any address to
 * *.exitname.exit. */
static void
clear_trackexithost_mappings(const char *exitname)
{
  char *suffix;
  size_t suffix_len;
  if (!addressmap || !exitname)
    return;
  suffix_len = strlen(exitname) + 16;
  suffix = tor_malloc(suffix_len);
  tor_snprintf(suffix, suffix_len, ".%s.exit", exitname);
  tor_strlower(suffix);

  STRMAP_FOREACH_MODIFY(addressmap, address, addressmap_entry_t *, ent) {
    if (ent->source == ADDRMAPSRC_TRACKEXIT && !strcmpend(address, suffix)) {
      addressmap_ent_remove(address, ent);
      MAP_DEL_CURRENT(address);
    }
  } STRMAP_FOREACH_END;
}

/** Remove all entries from the addressmap that were set via the
 * configuration file or the command line. */
void
addressmap_clear_configured(void)
{
  addressmap_get_mappings(NULL, 0, 0, 0);
}

/** Remove all entries from the addressmap that are set to expire, ever. */
void
addressmap_clear_transient(void)
{
  addressmap_get_mappings(NULL, 2, TIME_MAX, 0);
}

/** Clean out entries from the addressmap cache that were
 * added long enough ago that they are no longer valid.
 */
void
addressmap_clean(time_t now)
{
  addressmap_get_mappings(NULL, 2, now, 0);
}

/** Free all the elements in the addressmap, and free the addressmap

⌨️ 快捷键说明

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