Commit aef30547 authored by Nick Mathewson's avatar Nick Mathewson 🤹
Browse files

Add an option to limit the number of non-open client circuits.

This is mainly meant as a way to keep clients from accidentally
DOSing themselves by (e.g.) enabling IsolateDestAddr or
IsolateDestPort on a port that they use for HTTP.
parent 20c0581a
Loading
Loading
Loading
Loading
+35 −0
Original line number Diff line number Diff line
@@ -288,6 +288,27 @@ circuit_get_best(const edge_connection_t *conn,
  return best;
}

/** Return the number of not-yet-open general-purpose origin circuits. */
static int
count_pending_general_client_circuits(void)
{
  const circuit_t *circ;

  int count = 0;

  for (circ = global_circuitlist; circ; circ = circ->next) {
    if (circ->marked_for_close ||
        circ->state == CIRCUIT_STATE_OPEN ||
        circ->purpose != CIRCUIT_PURPOSE_C_GENERAL ||
        !CIRCUIT_IS_ORIGIN(circ))
      continue;

    ++count;
  }

  return count;
}

#if 0
/** Check whether, according to the policies in <b>options</b>, the
 * circuit <b>circ</b> makes sense. */
@@ -1347,6 +1368,20 @@ circuit_get_open_circ_or_launch(edge_connection_t *conn,
  if (!circ) {
    extend_info_t *extend_info=NULL;
    uint8_t new_circ_purpose;
    const int n_pending = count_pending_general_client_circuits();

    if (n_pending >= options->MaxClientCircuitsPending) {
      static ratelim_t delay_limit = RATELIM_INIT(10*60);
      char *m;
      if ((m = rate_limit_log(&delay_limit, approx_time()))) {
        log_notice(LD_APP, "We'd like to launch a circuit to handle a "
                   "connection, but we already have %d general-purpose client "
                   "circuits pending. Waiting until some finish.",
                   n_pending);
        tor_free(m);
      }
      return 0;
    }

    if (desired_circuit_purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) {
      /* need to pick an intro point */
+10 −0
Original line number Diff line number Diff line
@@ -315,6 +315,7 @@ static config_var_t _option_vars[] = {
  VAR("MapAddress",              LINELIST, AddressMap,           NULL),
  V(MaxAdvertisedBandwidth,      MEMUNIT,  "1 GB"),
  V(MaxCircuitDirtiness,         INTERVAL, "10 minutes"),
  V(MaxClientCircuitsPending,    UINT,     "32"),
  V(MaxOnionsPending,            UINT,     "100"),
  OBSOLETE("MonthlyAccountingStart"),
  V(MyFamily,                    STRING,   NULL),
@@ -3215,6 +3216,15 @@ options_validate(or_options_t *old_options, or_options_t *options,
    return -1;
  }

  if (options->MaxClientCircuitsPending <= 0 ||
      options->MaxClientCircuitsPending > MAX_MAX_CLIENT_CIRCUITS_PENDING) {
    tor_asprintf(msg,
                 "MaxClientCircuitsPending must be between 1 and %d, but "
                 "was set to %d", MAX_MAX_CLIENT_CIRCUITS_PENDING,
                 options->MaxClientCircuitsPending);
    return -1;
  }

  if (validate_ports_csv(options->FirewallPorts, "FirewallPorts", msg) < 0)
    return -1;

+5 −0
Original line number Diff line number Diff line
@@ -3230,6 +3230,11 @@ typedef struct {
  /** Should that file be group-readable? */
  int ControlPortFileGroupReadable;

#define MAX_MAX_CLIENT_CIRCUITS_PENDING 1024
  /** Maximum number of non-open general-purpose origin circuits to allow at
   * once. */
  int MaxClientCircuitsPending;

} or_options_t;

/** Persistent state for an onion router, as saved to disk. */