Commit 4b13c33c authored by Robert Ransom's avatar Robert Ransom
Browse files

Don't close HS client circs which are 'almost connected' on timeout

parent c6a8ee36
Loading
Loading
Loading
Loading

changes/bug1297b

0 → 100644
+12 −0
Original line number Diff line number Diff line
  o Minor bugfixes:

    - Don't close hidden service client circuits which have almost
      finished connecting to their destination when they reach the
      normal circuit-build timeout.  Previously, we would close
      introduction circuits which are waiting for an acknowledgement
      from the introduction-point relay and rendezvous circuits which
      have been specified in an INTRODUCE1 cell sent to a hidden
      service after the normal CBT; now, we mark them as 'timed out',
      and launch another rendezvous attempt in parallel.  Fixes part
      of bug 1297.
+52 −1
Original line number Diff line number Diff line
@@ -75,6 +75,11 @@ circuit_is_acceptable(const origin_circuit_t *origin_circ,
      return 0;
  }

  /* If this is a timed-out hidden service circuit, skip it. */
  if (origin_circ->hs_circ_has_timed_out) {
    return 0;
  }

  if (purpose == CIRCUIT_PURPOSE_C_GENERAL ||
      purpose == CIRCUIT_PURPOSE_C_REND_JOINED)
    if (circ->timestamp_dirty &&
@@ -351,7 +356,9 @@ circuit_expire_building(void)
   * circuit_build_times_get_initial_timeout() if we haven't computed
   * custom timeouts yet */
  struct timeval general_cutoff, begindir_cutoff, fourhop_cutoff,
    cannibalize_cutoff, close_cutoff, extremely_old_cutoff;
    cannibalize_cutoff, close_cutoff, extremely_old_cutoff,
    hs_extremely_old_cutoff;
  const or_options_t *options = get_options();
  struct timeval now;
  cpath_build_state_t *build_state;

@@ -371,6 +378,10 @@ circuit_expire_building(void)
  SET_CUTOFF(close_cutoff, circ_times.close_ms);
  SET_CUTOFF(extremely_old_cutoff, circ_times.close_ms*2 + 1000);

  SET_CUTOFF(hs_extremely_old_cutoff,
             MAX(circ_times.close_ms*2 + 1000,
                 options->SocksTimeout * 1000));

  while (next_circ) {
    struct timeval cutoff;
    victim = next_circ;
@@ -392,6 +403,9 @@ circuit_expire_building(void)
    else
      cutoff = general_cutoff;

    if (TO_ORIGIN_CIRCUIT(victim)->hs_circ_has_timed_out)
      cutoff = hs_extremely_old_cutoff;

    if (timercmp(&victim->timestamp_created, &cutoff, >))
      continue; /* it's still young, leave it alone */

@@ -497,6 +511,43 @@ circuit_expire_building(void)
      }
    }

    /* If this is a hidden-service circuit which is far enough along
     * in connecting to its destination, and we haven't already
     * flagged it as 'timed out', flag it as 'timed out' so we'll
     * launch another intro or rend circ, but don't mark it for close
     * yet.
     *
     * (Circs flagged as 'timed out' are given a much longer timeout
     * period above, so we won't close them in the next call to
     * circuit_expire_building.) */
    if (!(TO_ORIGIN_CIRCUIT(victim)->hs_circ_has_timed_out)) {
      switch (victim->purpose) {
      case CIRCUIT_PURPOSE_C_REND_READY:
        /* We only want to spare a rend circ if it has been specified in
         * an INTRODUCE1 cell sent to a hidden service.  A circ's
         * pending_final_cpath field is non-NULL iff it is a rend circ
         * and we have tried to send an INTRODUCE1 cell specifying it.
         * Thus, if the pending_final_cpath field *is* NULL, then we
         * want to not spare it. */
        if (TO_ORIGIN_CIRCUIT(victim)->build_state->pending_final_cpath ==
            NULL)
          break;
      case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT:
      case CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED:
        /* If we have reached this line, we want to spare the circ for now. */
        log_info(LD_CIRC,"Marking circ %s:%d:%d (state %d:%s, purpose %d) "
                 "as timed-out HS circ",
                 victim->n_conn->_base.address, victim->n_conn->_base.port,
                 victim->n_circ_id,
                 victim->state, circuit_state_to_string(victim->state),
                 victim->purpose);
        TO_ORIGIN_CIRCUIT(victim)->hs_circ_has_timed_out = 1;
        continue;
      default:
        break;
      }
    }

    if (victim->n_conn)
      log_info(LD_CIRC,"Abandoning circ %s:%d:%d (state %d:%s, purpose %d)",
               victim->n_conn->_base.address, victim->n_conn->_base.port,
+7 −0
Original line number Diff line number Diff line
@@ -2607,6 +2607,13 @@ typedef struct origin_circuit_t {
   * cannibalized circuits. */
  unsigned int has_opened : 1;

  /** Set iff this is a hidden-service circuit which has timed out
   * according to our current circuit-build timeout, but which has
   * been kept around because it might still succeed in connecting to
   * its destination, and which is not a fully-connected rendezvous
   * circuit. */
  unsigned int hs_circ_has_timed_out : 1;

  /** What commands were sent over this circuit that decremented the
   * RELAY_EARLY counter? This is for debugging task 878. */
  uint8_t relay_early_commands[MAX_RELAY_EARLY_CELLS_PER_CIRCUIT];
+5 −0
Original line number Diff line number Diff line
@@ -895,6 +895,11 @@ rend_client_receive_rendezvous(origin_circuit_t *circ, const uint8_t *request,
  hop->package_window = circuit_initial_package_window();
  hop->deliver_window = CIRCWINDOW_START;

  /* Now that this circuit has finished connecting to its destination,
   * make sure circuit_get_open_circ_or_launch is willing to return it
   * so we can actually use it. */
  circ->hs_circ_has_timed_out = 0;

  onion_append_to_cpath(&circ->cpath, hop);
  circ->build_state->pending_final_cpath = NULL; /* prevent double-free */