Commit 6c69b16c authored by Nick Mathewson's avatar Nick Mathewson 🥔
Browse files

Use new wrappers for making,sending,processing create/extend cells

parent 2802ccae
Loading
Loading
Loading
Loading
+86 −83
Original line number Diff line number Diff line
@@ -55,9 +55,7 @@ static channel_t * channel_connect_for_circuit(const tor_addr_t *addr,
                                               uint16_t port,
                                               const char *id_digest);
static int circuit_deliver_create_cell(circuit_t *circ,
                                       uint8_t cell_type,
                                       const uint8_t *payload,
                                       size_t payload_len);
                                       const create_cell_t *create_cell);
static int onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit);
static crypt_path_t *onion_next_hop_in_cpath(crypt_path_t *cpath);
static int onion_extend_cpath(origin_circuit_t *circ);
@@ -474,15 +472,13 @@ circuit_n_chan_done(channel_t *chan, int status)
           *     died? */
        }
      } else {
        /* pull the create cell out of circ->onionskin, and send it */
        tor_assert(circ->n_chan_onionskin);
        if (circuit_deliver_create_cell(circ,CELL_CREATE,
                                        (const uint8_t*)circ->n_chan_onionskin,
                                        circ->n_chan_onionskin_len)<0) {
        /* pull the create cell out of circ->n_chan_create_cell, and send it */
        tor_assert(circ->n_chan_create_cell);
        if (circuit_deliver_create_cell(circ, circ->n_chan_create_cell)<0) {
          circuit_mark_for_close(circ, END_CIRC_REASON_RESOURCELIMIT);
          continue;
        }
        tor_free(circ->n_chan_onionskin);
        tor_free(circ->n_chan_create_cell);
        circuit_set_state(circ, CIRCUIT_STATE_OPEN);
      }
    }
@@ -499,16 +495,17 @@ circuit_n_chan_done(channel_t *chan, int status)
 * Return -1 if we failed to find a suitable circid, else return 0.
 */
static int
circuit_deliver_create_cell(circuit_t *circ, uint8_t cell_type,
                            const uint8_t *payload, size_t payload_len)
circuit_deliver_create_cell(circuit_t *circ, const create_cell_t *create_cell)
{
  cell_t cell;
  circid_t id;

  tor_assert(circ);
  tor_assert(circ->n_chan);
  tor_assert(payload);
  tor_assert(cell_type == CELL_CREATE || cell_type == CELL_CREATE_FAST);
  tor_assert(create_cell);
  tor_assert(create_cell->cell_type == CELL_CREATE ||
             create_cell->cell_type == CELL_CREATE_FAST ||
             create_cell->cell_type == CELL_CREATE2);

  id = get_unique_circ_id_by_chan(circ->n_chan);
  if (!id) {
@@ -519,10 +516,12 @@ circuit_deliver_create_cell(circuit_t *circ, uint8_t cell_type,
  circuit_set_n_circid_chan(circ, id, circ->n_chan);

  memset(&cell, 0, sizeof(cell_t));
  cell.command = cell_type;
  if (create_cell_format(&cell, create_cell) < 0) {
    log_warn(LD_CIRC,"Couldn't format create cell");
    return -1;
  }
  cell.circ_id = circ->n_circ_id;

  memcpy(cell.payload, payload, payload_len);
  append_cell_to_circuit_queue(circ, circ->n_chan, &cell,
                               CELL_DIRECTION_OUT, 0);

@@ -615,18 +614,16 @@ circuit_send_next_onion_skin(origin_circuit_t *circ)
{
  crypt_path_t *hop;
  const node_t *node;
  uint8_t payload[2+4+DIGEST_LEN+MAX_ONIONSKIN_CHALLENGE_LEN];
  uint8_t *onionskin;
  uint16_t handshake_type;
  int onionskin_len;
  size_t payload_len;

  tor_assert(circ);

  if (circ->cpath->state == CPATH_STATE_CLOSED) {
    /* This is the first hop. */
    create_cell_t cc;
    int fast;
    uint8_t cell_type;
    int len;
    log_debug(LD_CIRC,"First skin; sending create cell.");
    memset(&cc, 0, sizeof(cc));
    if (circ->build_state->onehop_tunnel)
      control_event_bootstrap(BOOTSTRAP_STATUS_ONEHOP_CREATE, 0);
    else
@@ -638,30 +635,29 @@ circuit_send_next_onion_skin(origin_circuit_t *circ)
      /* We are an OR and we know the right onion key: we should
       * send an old slow create cell.
       */
      cell_type = CELL_CREATE;
      handshake_type = ONION_HANDSHAKE_TYPE_TAP;
      cc.cell_type = CELL_CREATE;
      cc.handshake_type = ONION_HANDSHAKE_TYPE_TAP;
      note_request("cell: create", 1);
    } else {
      /* We are not an OR, and we're building the first hop of a circuit to a
       * new OR: we can be speedy and use CREATE_FAST to save an RSA operation
       * and a DH operation. */
      cell_type = CELL_CREATE_FAST;
      handshake_type = ONION_HANDSHAKE_TYPE_FAST;
      cc.cell_type = CELL_CREATE_FAST;
      cc.handshake_type = ONION_HANDSHAKE_TYPE_FAST;
      note_request("cell: create fast", 1);
    }

    memset(payload, 0, sizeof(payload));
    onionskin_len = onion_skin_create(handshake_type,
    len = onion_skin_create(cc.handshake_type,
                            circ->cpath->extend_info,
                            &circ->cpath->handshake_state,
                                      payload);
    if (onionskin_len < 0) {
                            cc.onionskin);
    if (len < 0) {
      log_warn(LD_CIRC,"onion_skin_create (first hop) failed.");
      return - END_CIRC_REASON_INTERNAL;
    }
    cc.handshake_len = len;

    if (circuit_deliver_create_cell(TO_CIRCUIT(circ), cell_type, payload,
                                    onionskin_len) < 0)
    if (circuit_deliver_create_cell(TO_CIRCUIT(circ), &cc) < 0)
      return - END_CIRC_REASON_RESOURCELIMIT;

    circ->cpath->state = CPATH_STATE_AWAITING_KEYS;
@@ -670,10 +666,13 @@ circuit_send_next_onion_skin(origin_circuit_t *circ)
             fast ? "CREATE_FAST" : "CREATE",
             node ? node_describe(node) : "<unnamed>");
  } else {
    extend_cell_t ec;
    int len;
    tor_assert(circ->cpath->state == CPATH_STATE_OPEN);
    tor_assert(circ->base_.state == CIRCUIT_STATE_BUILDING);
    log_debug(LD_CIRC,"starting to send subsequent skin.");
    hop = onion_next_hop_in_cpath(circ->cpath);
    memset(&ec, 0, sizeof(ec));
    if (!hop) {
      /* done building the circuit. whew. */
      circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_OPEN);
@@ -743,34 +742,44 @@ circuit_send_next_onion_skin(origin_circuit_t *circ)
      return - END_CIRC_REASON_INTERNAL;
    }

    set_uint32(payload, tor_addr_to_ipv4n(&hop->extend_info->addr));
    set_uint16(payload+4, htons(hop->extend_info->port));

    onionskin = payload+2+4;
    memcpy(payload+2+4+TAP_ONIONSKIN_CHALLENGE_LEN,
           hop->extend_info->identity_digest, DIGEST_LEN);
    payload_len = 2+4+TAP_ONIONSKIN_CHALLENGE_LEN+DIGEST_LEN;
    ec.cell_type = RELAY_COMMAND_EXTEND;
    tor_addr_copy(&ec.orport_ipv4.addr, &hop->extend_info->addr);
    ec.orport_ipv4.port = hop->extend_info->port;
    tor_addr_make_unspec(&ec.orport_ipv6.addr);
    memcpy(ec.node_id, hop->extend_info->identity_digest, DIGEST_LEN);

    handshake_type = ONION_HANDSHAKE_TYPE_TAP;
    ec.create_cell.handshake_type = ONION_HANDSHAKE_TYPE_TAP;
    ec.create_cell.cell_type = CELL_CREATE;

    if (onion_skin_create(handshake_type,
    len = onion_skin_create(ec.create_cell.handshake_type,
                            hop->extend_info,
                            &hop->handshake_state,
                          onionskin) < 0) {
                            ec.create_cell.onionskin);
    if (len < 0) {
      log_warn(LD_CIRC,"onion_skin_create failed.");
      return - END_CIRC_REASON_INTERNAL;
    }
    ec.create_cell.handshake_len = len;

    log_info(LD_CIRC,"Sending extend relay cell.");
    note_request("cell: extend", 1);
    {
      uint8_t command = 0;
      uint16_t payload_len=0;
      uint8_t payload[RELAY_PAYLOAD_SIZE];
      if (extend_cell_format(&command, &payload_len, payload, &ec)<0) {
        log_warn(LD_CIRC,"Couldn't format extend cell");
        return -END_CIRC_REASON_INTERNAL;
      }

      /* send it to hop->prev, because it will transfer
       * it to a create cell and then send to hop */
      if (relay_send_command_from_edge(0, TO_CIRCUIT(circ),
                                     RELAY_COMMAND_EXTEND,
                                       command,
                                       (char*)payload, payload_len,
                                       hop->prev) < 0)
        return 0; /* circuit is closed */

    }
    hop->state = CPATH_STATE_AWAITING_KEYS;
  }
  return 0;
@@ -809,11 +818,7 @@ circuit_extend(cell_t *cell, circuit_t *circ)
{
  channel_t *n_chan;
  relay_header_t rh;
  char *onionskin;
  char *id_digest=NULL;
  uint32_t n_addr32;
  uint16_t n_port;
  tor_addr_t n_addr;
  extend_cell_t ec;
  const char *msg = NULL;
  int should_launch = 0;

@@ -836,27 +841,21 @@ circuit_extend(cell_t *cell, circuit_t *circ)

  relay_header_unpack(&rh, cell->payload);

  if (rh.length < 4+2+TAP_ONIONSKIN_CHALLENGE_LEN+DIGEST_LEN) {
  if (extend_cell_parse(&ec, rh.command,
                        cell->payload+RELAY_HEADER_SIZE,
                        rh.length) < 0) {
    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
           "Wrong length %d on extend cell. Closing circuit.",
           rh.length);
           "Can't parse extend cell. Closing circuit.");
    return -1;
  }

  n_addr32 = ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE));
  n_port = ntohs(get_uint16(cell->payload+RELAY_HEADER_SIZE+4));
  onionskin = (char*) cell->payload+RELAY_HEADER_SIZE+4+2;
  id_digest = (char*) cell->payload+RELAY_HEADER_SIZE+4+2+
    TAP_ONIONSKIN_CHALLENGE_LEN;
  tor_addr_from_ipv4h(&n_addr, n_addr32);

  if (!n_port || !n_addr32) {
  if (!ec.orport_ipv4.port || tor_addr_is_null(&ec.orport_ipv4.addr)) {
    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
           "Client asked me to extend to zero destination port or addr.");
    return -1;
  }

  if (tor_addr_is_internal(&n_addr, 0) &&
  if (tor_addr_is_internal(&ec.orport_ipv4.addr, 0) &&
      !get_options()->ExtendAllowPrivateAddresses) {
    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
           "Client asked me to extend to a private address");
@@ -869,7 +868,7 @@ circuit_extend(cell_t *cell, circuit_t *circ)
   * fingerprints -- a) because it opens the user up to a mitm attack,
   * and b) because it lets an attacker force the relay to hold open a
   * new TLS connection for each extend request. */
  if (tor_digest_is_zero(id_digest)) {
  if (tor_digest_is_zero((const char*)ec.node_id)) {
    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
           "Client asked me to extend without specifying an id_digest.");
    return -1;
@@ -878,7 +877,7 @@ circuit_extend(cell_t *cell, circuit_t *circ)
  /* Next, check if we're being asked to connect to the hop that the
   * extend cell came from. There isn't any reason for that, and it can
   * assist circular-path attacks. */
  if (tor_memeq(id_digest,
  if (tor_memeq(ec.node_id,
                TO_OR_CIRCUIT(circ)->p_chan->identity_digest,
                DIGEST_LEN)) {
    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
@@ -886,29 +885,34 @@ circuit_extend(cell_t *cell, circuit_t *circ)
    return -1;
  }

  n_chan = channel_get_for_extend(id_digest,
                                  &n_addr,
  n_chan = channel_get_for_extend((const char*)ec.node_id,
                                  &ec.orport_ipv4.addr,
                                  &msg,
                                  &should_launch);

  if (!n_chan) {
    log_debug(LD_CIRC|LD_OR,"Next router (%s): %s",
              fmt_addrport(&n_addr, n_port), msg?msg:"????");
              fmt_addrport(&ec.orport_ipv4.addr,ec.orport_ipv4.port),
              msg?msg:"????");

    circ->n_hop = extend_info_new(NULL /*nickname*/,
                                    id_digest,
                                  (const char*)ec.node_id,
                                  NULL /*onion_key*/,
                                    &n_addr, n_port);
                                  &ec.orport_ipv4.addr,
                                  ec.orport_ipv4.port);

    circ->n_chan_onionskin = tor_malloc(TAP_ONIONSKIN_CHALLENGE_LEN);
    memcpy(circ->n_chan_onionskin, onionskin, TAP_ONIONSKIN_CHALLENGE_LEN);
    circ->n_chan_onionskin_len = TAP_ONIONSKIN_CHALLENGE_LEN;
    /* XXXX Make sure we can eventually deliver create cell with weird
     * content */
    circ->n_chan_create_cell = tor_memdup(&ec.create_cell,
                                          sizeof(ec.create_cell));

    circuit_set_state(circ, CIRCUIT_STATE_CHAN_WAIT);

    if (should_launch) {
      /* we should try to open a connection */
      n_chan = channel_connect_for_circuit(&n_addr, n_port, id_digest);
      n_chan = channel_connect_for_circuit(&ec.orport_ipv4.addr,
                                           ec.orport_ipv4.port,
                                           (const char*)ec.node_id);
      if (!n_chan) {
        log_info(LD_CIRC,"Launching n_chan failed. Closing circuit.");
        circuit_mark_for_close(circ, END_CIRC_REASON_CONNECTFAILED);
@@ -929,8 +933,7 @@ circuit_extend(cell_t *cell, circuit_t *circ)
            "n_chan is %s",
            channel_get_canonical_remote_descr(n_chan));

  if (circuit_deliver_create_cell(circ, CELL_CREATE, (uint8_t*)onionskin,
                                  TAP_ONIONSKIN_CHALLENGE_LEN) < 0)
  if (circuit_deliver_create_cell(circ, &ec.create_cell) < 0)
    return -1;
  return 0;
}
+3 −3
Original line number Diff line number Diff line
@@ -252,7 +252,7 @@ circuit_set_state(circuit_t *circ, uint8_t state)
    smartlist_add(circuits_pending_chans, circ);
  }
  if (state == CIRCUIT_STATE_OPEN)
    tor_assert(!circ->n_chan_onionskin);
    tor_assert(!circ->n_chan_create_cell);
  circ->state = state;
}

@@ -674,7 +674,7 @@ circuit_free(circuit_t *circ)
  }

  extend_info_free(circ->n_hop);
  tor_free(circ->n_chan_onionskin);
  tor_free(circ->n_chan_create_cell);

  /* Remove from map. */
  circuit_set_n_circid_chan(circ, 0, NULL);
@@ -1582,7 +1582,7 @@ assert_circuit_ok(const circuit_t *c)
  tor_assert(c->deliver_window >= 0);
  tor_assert(c->package_window >= 0);
  if (c->state == CIRCUIT_STATE_OPEN) {
    tor_assert(!c->n_chan_onionskin);
    tor_assert(!c->n_chan_create_cell);
    if (or_circ) {
      tor_assert(or_circ->n_crypto);
      tor_assert(or_circ->p_crypto);
+4 −5
Original line number Diff line number Diff line
@@ -2645,6 +2645,8 @@ typedef struct {
#define ORIGIN_CIRCUIT_MAGIC 0x35315243u
#define OR_CIRCUIT_MAGIC 0x98ABC04Fu

struct create_cell_t;

/**
 * A circuit is a path over the onion routing
 * network. Applications can connect to one end of the circuit, and can
@@ -2719,11 +2721,8 @@ typedef struct circuit_t {
   * more. */
  int deliver_window;

  uint8_t n_chan_onionskin_len; /* XXXX MAKE THIS GET USED. */
  /** For storage while n_chan is pending
    * (state CIRCUIT_STATE_CHAN_WAIT). When defined, it is always
    * length n_chan_onionskin_len */
  char *n_chan_onionskin;
  /** For storage while n_chan is pending (state CIRCUIT_STATE_CHAN_WAIT). */
  struct create_cell_t *n_chan_create_cell;

  /** When was this circuit created?  We keep this timestamp with a higher
   * resolution than most so that the circuit-build-time tracking code can