示例#1
0
static void
test_channel_for_extend(void *arg)
{
  channel_t *chan1 = NULL, *chan2 = NULL;
  channel_t *ret_chan = NULL;
  char digest[DIGEST_LEN];
  ed25519_public_key_t ed_id;
  tor_addr_t addr;
  const char *msg;
  int launch;
  time_t now = time(NULL);

  (void) arg;

  memset(digest, 'A', sizeof(digest));
  memset(&ed_id, 'B', sizeof(ed_id));

  chan1 = new_fake_channel();
  tt_assert(chan1);
  /* Need to be registered to get added to the id map. */
  channel_register(chan1);
  tt_int_op(chan1->registered, OP_EQ, 1);
  /* We need those for the test. */
  chan1->is_canonical = test_chan_is_canonical;
  chan1->matches_target = test_chan_matches_target;
  chan1->timestamp_created = now - 9;

  chan2 = new_fake_channel();
  tt_assert(chan2);
  /* Need to be registered to get added to the id map. */
  channel_register(chan2);
  tt_int_op(chan2->registered, OP_EQ, 1);
  /* We need those for the test. */
  chan2->is_canonical = test_chan_is_canonical;
  chan2->matches_target = test_chan_matches_target;
  /* Make it older than chan1. */
  chan2->timestamp_created = chan1->timestamp_created - 1;

  /* Set channel identities and add it to the channel map. The last one to be
   * added is made the first one in the list so the lookup will always return
   * that one first. */
  channel_set_identity_digest(chan2, digest, &ed_id);
  channel_set_identity_digest(chan1, digest, &ed_id);
  tt_ptr_op(channel_find_by_remote_identity(digest, NULL), OP_EQ, chan1);
  tt_ptr_op(channel_find_by_remote_identity(digest, &ed_id), OP_EQ, chan1);

  /* The expected result is chan2 because it is older than chan1. */
  ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
  tt_assert(ret_chan);
  tt_ptr_op(ret_chan, OP_EQ, chan2);
  tt_int_op(launch, OP_EQ, 0);
  tt_str_op(msg, OP_EQ, "Connection is fine; using it.");

  /* Switch that around from previous test. */
  chan2->timestamp_created = chan1->timestamp_created + 1;
  ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
  tt_assert(ret_chan);
  tt_ptr_op(ret_chan, OP_EQ, chan1);
  tt_int_op(launch, OP_EQ, 0);
  tt_str_op(msg, OP_EQ, "Connection is fine; using it.");

  /* Same creation time, num circuits will be used and they both have 0 so the
   * channel 2 should be picked due to how channel_is_better() work. */
  chan2->timestamp_created = chan1->timestamp_created;
  ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
  tt_assert(ret_chan);
  tt_ptr_op(ret_chan, OP_EQ, chan1);
  tt_int_op(launch, OP_EQ, 0);
  tt_str_op(msg, OP_EQ, "Connection is fine; using it.");

  /* For the rest of the tests, we need channel 1 to be the older. */
  chan2->timestamp_created = chan1->timestamp_created + 1;

  /* Condemned the older channel. */
  chan1->state = CHANNEL_STATE_CLOSING;
  ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
  tt_assert(ret_chan);
  tt_ptr_op(ret_chan, OP_EQ, chan2);
  tt_int_op(launch, OP_EQ, 0);
  tt_str_op(msg, OP_EQ, "Connection is fine; using it.");
  chan1->state = CHANNEL_STATE_OPEN;

  /* Make the older channel a client one. */
  channel_mark_client(chan1);
  ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
  tt_assert(ret_chan);
  tt_ptr_op(ret_chan, OP_EQ, chan2);
  tt_int_op(launch, OP_EQ, 0);
  tt_str_op(msg, OP_EQ, "Connection is fine; using it.");
  channel_clear_client(chan1);

  /* Non matching ed identity with valid digest. */
  ed25519_public_key_t dumb_ed_id;
  memset(&dumb_ed_id, 0, sizeof(dumb_ed_id));
  ret_chan = channel_get_for_extend(digest, &dumb_ed_id, &addr, &msg,
                                    &launch);
  tt_assert(!ret_chan);
  tt_str_op(msg, OP_EQ, "Not connected. Connecting.");
  tt_int_op(launch, OP_EQ, 1);

  /* Opening channel, we'll check if the target address matches. */
  test_chan_should_match_target = 1;
  chan1->state = CHANNEL_STATE_OPENING;
  chan2->state = CHANNEL_STATE_OPENING;
  ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
  tt_assert(!ret_chan);
  tt_str_op(msg, OP_EQ, "Connection in progress; waiting.");
  tt_int_op(launch, OP_EQ, 0);
  chan1->state = CHANNEL_STATE_OPEN;
  chan2->state = CHANNEL_STATE_OPEN;

  /* Mark channel 1 as bad for circuits. */
  channel_mark_bad_for_new_circs(chan1);
  ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
  tt_assert(ret_chan);
  tt_ptr_op(ret_chan, OP_EQ, chan2);
  tt_int_op(launch, OP_EQ, 0);
  tt_str_op(msg, OP_EQ, "Connection is fine; using it.");
  chan1->is_bad_for_new_circs = 0;

  /* Mark both channels as unusable. */
  channel_mark_bad_for_new_circs(chan1);
  channel_mark_bad_for_new_circs(chan2);
  ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
  tt_assert(!ret_chan);
  tt_str_op(msg, OP_EQ, "Connections all too old, or too non-canonical. "
                        " Launching a new one.");
  tt_int_op(launch, OP_EQ, 1);
  chan1->is_bad_for_new_circs = 0;
  chan2->is_bad_for_new_circs = 0;

  /* Non canonical channels. */
  test_chan_should_match_target = 0;
  test_chan_canonical_should_be_reliable = 1;
  ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
  tt_assert(!ret_chan);
  tt_str_op(msg, OP_EQ, "Connections all too old, or too non-canonical. "
                        " Launching a new one.");
  tt_int_op(launch, OP_EQ, 1);

 done:
  free_fake_channel(chan1);
  free_fake_channel(chan2);
}
示例#2
0
/** Process a 'create' <b>cell</b> that just arrived from <b>chan</b>. Make a
 * new circuit with the p_circ_id specified in cell. Put the circuit in state
 * onionskin_pending, and pass the onionskin to the cpuworker. Circ will get
 * picked up again when the cpuworker finishes decrypting it.
 */
static void
command_process_create_cell(cell_t *cell, channel_t *chan)
{
  or_circuit_t *circ;
  const or_options_t *options = get_options();
  int id_is_high;

  tor_assert(cell);
  tor_assert(chan);

  log_debug(LD_OR,
            "Got a CREATE cell for circ_id %d on channel " U64_FORMAT
            " (%p)",
            cell->circ_id,
            U64_PRINTF_ARG(chan->global_identifier), chan);

  if (we_are_hibernating()) {
    log_info(LD_OR,
             "Received create cell but we're shutting down. Sending back "
             "destroy.");
    channel_send_destroy(cell->circ_id, chan,
                               END_CIRC_REASON_HIBERNATING);
    return;
  }

  if (!server_mode(options) ||
      (!public_server_mode(options) && channel_is_outgoing(chan))) {
    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
           "Received create cell (type %d) from %s, but we're connected "
           "to it as a client. "
           "Sending back a destroy.",
           (int)cell->command, channel_get_canonical_remote_descr(chan));
    channel_send_destroy(cell->circ_id, chan,
                         END_CIRC_REASON_TORPROTOCOL);
    return;
  }

  /* If the high bit of the circuit ID is not as expected, close the
   * circ. */
  id_is_high = cell->circ_id & (1<<15);
  if ((id_is_high &&
       chan->circ_id_type == CIRC_ID_TYPE_HIGHER) ||
      (!id_is_high &&
       chan->circ_id_type == CIRC_ID_TYPE_LOWER)) {
    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
           "Received create cell with unexpected circ_id %d. Closing.",
           cell->circ_id);
    channel_send_destroy(cell->circ_id, chan,
                         END_CIRC_REASON_TORPROTOCOL);
    return;
  }

  if (circuit_id_in_use_on_channel(cell->circ_id, chan)) {
    const node_t *node = node_get_by_id(chan->identity_digest);
    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
           "Received CREATE cell (circID %d) for known circ. "
           "Dropping (age %d).",
           cell->circ_id, (int)(time(NULL) - channel_when_created(chan)));
    if (node) {
      char *p = esc_for_log(node_get_platform(node));
      log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
             "Details: router %s, platform %s.",
             node_describe(node), p);
      tor_free(p);
    }
    return;
  }

  circ = or_circuit_new(cell->circ_id, chan);
  circ->base_.purpose = CIRCUIT_PURPOSE_OR;
  circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_ONIONSKIN_PENDING);
  if (cell->command == CELL_CREATE) {
    char *onionskin = tor_malloc(ONIONSKIN_CHALLENGE_LEN);
    memcpy(onionskin, cell->payload, ONIONSKIN_CHALLENGE_LEN);

    /* hand it off to the cpuworkers, and then return. */
    if (assign_onionskin_to_cpuworker(NULL, circ, onionskin) < 0) {
      log_debug(LD_GENERAL,"Failed to hand off onionskin. Closing.");
      circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_RESOURCELIMIT);
      return;
    }
    log_debug(LD_OR,"success: handed off onionskin.");
  } else {
    /* This is a CREATE_FAST cell; we can handle it immediately without using
     * a CPU worker. */
    char keys[CPATH_KEY_MATERIAL_LEN];
    char reply[DIGEST_LEN*2];

    tor_assert(cell->command == CELL_CREATE_FAST);

    /* Make sure we never try to use the OR connection on which we
     * received this cell to satisfy an EXTEND request,  */
    channel_mark_client(chan);

    if (fast_server_handshake(cell->payload, (uint8_t*)reply,
                              (uint8_t*)keys, sizeof(keys))<0) {
      log_warn(LD_OR,"Failed to generate key material. Closing.");
      circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
      return;
    }
    if (onionskin_answer(circ, CELL_CREATED_FAST, reply, keys)<0) {
      log_warn(LD_OR,"Failed to reply to CREATE_FAST cell. Closing.");
      circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
      return;
    }
  }
}
示例#3
0
/** Process a 'create' <b>cell</b> that just arrived from <b>chan</b>. Make a
 * new circuit with the p_circ_id specified in cell. Put the circuit in state
 * onionskin_pending, and pass the onionskin to the cpuworker. Circ will get
 * picked up again when the cpuworker finishes decrypting it.
 */
static void
command_process_create_cell(cell_t *cell, channel_t *chan)
{
  or_circuit_t *circ;
  const or_options_t *options = get_options();
  int id_is_high;
  create_cell_t *create_cell;

  tor_assert(cell);
  tor_assert(chan);

  log_debug(LD_OR,
            "Got a CREATE cell for circ_id %u on channel " U64_FORMAT
            " (%p)",
            (unsigned)cell->circ_id,
            U64_PRINTF_ARG(chan->global_identifier), chan);

  if (we_are_hibernating()) {
    log_info(LD_OR,
             "Received create cell but we're shutting down. Sending back "
             "destroy.");
    channel_send_destroy(cell->circ_id, chan,
                               END_CIRC_REASON_HIBERNATING);
    return;
  }

  if (!server_mode(options) ||
      (!public_server_mode(options) && channel_is_outgoing(chan))) {
    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
           "Received create cell (type %d) from %s, but we're connected "
           "to it as a client. "
           "Sending back a destroy.",
           (int)cell->command, channel_get_canonical_remote_descr(chan));
    channel_send_destroy(cell->circ_id, chan,
                         END_CIRC_REASON_TORPROTOCOL);
    return;
  }

  if (cell->circ_id == 0) {
    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
           "Received a create cell (type %d) from %s with zero circID; "
           " ignoring.", (int)cell->command,
           channel_get_actual_remote_descr(chan));
    return;
  }

  /* If the high bit of the circuit ID is not as expected, close the
   * circ. */
  if (chan->wide_circ_ids)
    id_is_high = cell->circ_id & (1u<<31);
  else
    id_is_high = cell->circ_id & (1u<<15);
  if ((id_is_high &&
       chan->circ_id_type == CIRC_ID_TYPE_HIGHER) ||
      (!id_is_high &&
       chan->circ_id_type == CIRC_ID_TYPE_LOWER)) {
    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
           "Received create cell with unexpected circ_id %u. Closing.",
           (unsigned)cell->circ_id);
    channel_send_destroy(cell->circ_id, chan,
                         END_CIRC_REASON_TORPROTOCOL);
    return;
  }

  if (circuit_id_in_use_on_channel(cell->circ_id, chan)) {
    const node_t *node = node_get_by_id(chan->identity_digest);
    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
           "Received CREATE cell (circID %u) for known circ. "
           "Dropping (age %d).",
           (unsigned)cell->circ_id,
           (int)(time(NULL) - channel_when_created(chan)));
    if (node) {
      char *p = esc_for_log(node_get_platform(node));
      log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
             "Details: router %s, platform %s.",
             node_describe(node), p);
      tor_free(p);
    }
    return;
  }

  circ = or_circuit_new(cell->circ_id, chan);
  circ->base_.purpose = CIRCUIT_PURPOSE_OR;
  circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_ONIONSKIN_PENDING);
  create_cell = tor_malloc_zero(sizeof(create_cell_t));
  if (create_cell_parse(create_cell, cell) < 0) {
    tor_free(create_cell);
    log_fn(LOG_PROTOCOL_WARN, LD_OR,
           "Bogus/unrecognized create cell; closing.");
    circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
    return;
  }

  if (create_cell->handshake_type != ONION_HANDSHAKE_TYPE_FAST) {
    /* hand it off to the cpuworkers, and then return. */
    if (connection_or_digest_is_known_relay(chan->identity_digest))
      rep_hist_note_circuit_handshake_requested(create_cell->handshake_type);
    if (assign_onionskin_to_cpuworker(NULL, circ, create_cell) < 0) {
      log_debug(LD_GENERAL,"Failed to hand off onionskin. Closing.");
      circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_RESOURCELIMIT);
      return;
    }
    log_debug(LD_OR,"success: handed off onionskin.");
  } else {
    /* This is a CREATE_FAST cell; we can handle it immediately without using
     * a CPU worker. */
    uint8_t keys[CPATH_KEY_MATERIAL_LEN];
    uint8_t rend_circ_nonce[DIGEST_LEN];
    int len;
    created_cell_t created_cell;

    /* Make sure we never try to use the OR connection on which we
     * received this cell to satisfy an EXTEND request,  */
    channel_mark_client(chan);

    memset(&created_cell, 0, sizeof(created_cell));
    len = onion_skin_server_handshake(ONION_HANDSHAKE_TYPE_FAST,
                                       create_cell->onionskin,
                                       create_cell->handshake_len,
                                       NULL,
                                       created_cell.reply,
                                       keys, CPATH_KEY_MATERIAL_LEN,
                                       rend_circ_nonce);
    tor_free(create_cell);
    if (len < 0) {
      log_warn(LD_OR,"Failed to generate key material. Closing.");
      circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
      tor_free(create_cell);
      return;
    }
    created_cell.cell_type = CELL_CREATED_FAST;
    created_cell.handshake_len = len;

    if (onionskin_answer(circ, &created_cell,
                         (const char *)keys, rend_circ_nonce)<0) {
      log_warn(LD_OR,"Failed to reply to CREATE_FAST cell. Closing.");
      circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
      return;
    }
    memwipe(keys, 0, sizeof(keys));
  }
}