Commit 57f7c852 authored by Nick Mathewson's avatar Nick Mathewson 🐘
Browse files

r16282@catbus: nickm | 2007-10-30 14:28:58 -0400

 Implement lots of proposal 105.  None of it is enabled yet.


svn:r12285
parent c0c2001a
Loading
Loading
Loading
Loading
+11 −6
Changes for doc/TODO: 11 added lines, 6 removed lines.
Original line number Diff line number Diff line
@@ -42,16 +42,21 @@ Things we'd like to do in 0.2.0.x:
    - 105+TLS, if possible.
      - 105 only
        - Need to get a finished proposal 105
        - "Pick a version" function
        o "Pick a version" function
        - Have a 'waiting_for_version' state.
        - Store version in or_connection_t.
        - Generate netinfo cells
        - Accept netinfo cells
        o Store version in or_connection_t.
        o Generate netinfo cells
        o Accept netinfo cells
        . Add an is_canonical field to or_connection_t.
          o Set it when we get a match in the netinfo.
          o Set it when we get a match for a routerinfo we have.
          - Don't extend a circuit over a noncanonical connection with
            mismatched address.
        - Version negotiation: send a version cell and enter
          waiting-for-version; when version cell arrives, pick version
          and send netinfo and be "open".
        - On netinfo, warn if there's skew from a server.
        - Handle IP addresses in netinfo properly.
        o On netinfo, warn if there's skew from a server.
        - Learn our outgoing IP address from netinfo cells?
      - TLS only
        - Need to get a finished TLS normalization proposal
        - Revised authentication.
+5 −2
Changes for doc/spec/proposals/105-handshake-revision.txt: 5 added lines, 2 removed lines.
Original line number Diff line number Diff line
@@ -4,7 +4,7 @@ Version: $Revision$
Last-Modified: $Date$
Author: Nick Mathewson, Roger Dingledine
Created:
Status: Open
Status: Accepted

Overview:

@@ -120,7 +120,7 @@ Proposal:
   When a Tor connection is established, both parties normally send a
   VERSIONS cell before sending any other cells.  (But see below.)

         VersionsLen          [1 byte]
         VersionsLen          [2 byte]
         Versions             [VersionsLen bytes]

   "Versions" is a sequence of VersionsLen bytes.  Each value between 1 and
@@ -157,6 +157,8 @@ Proposal:
   The VERSIONS cell must be sent as a v1 cell (2 bytes of circuitID, 1
   byte of command, 509 bytes of payload).

   [NOTE: The VERSIONS cell is assigned the command number 7.]

2.2. MITM-prevention and time checking

   If we negotiate a v2 connection or higher, the second cell we send SHOULD
@@ -195,6 +197,7 @@ Proposal:
   given in the EXTEND cell is not listed in the NETINFO cell, the first
   party SHOULD close the connection as a likely MITM attack.

   [NOTE: The NETINFO cell is assigned the command number 8.]

Discussion: Versions versus feature lists

+135 −30
Changes for src/or/command.c: 135 added lines, 30 removed lines.
Original line number Diff line number Diff line
@@ -25,12 +25,16 @@ uint64_t stats_n_create_cells_processed = 0;
uint64_t stats_n_created_cells_processed = 0;
uint64_t stats_n_relay_cells_processed = 0;
uint64_t stats_n_destroy_cells_processed = 0;
uint64_t stats_n_versions_cells_processed = 0;
uint64_t stats_n_netinfo_cells_processed = 0;

/* These are the main four functions for processing cells */
/* These are the main functions for processing cells */
static void command_process_create_cell(cell_t *cell, or_connection_t *conn);
static void command_process_created_cell(cell_t *cell, or_connection_t *conn);
static void command_process_relay_cell(cell_t *cell, or_connection_t *conn);
static void command_process_destroy_cell(cell_t *cell, or_connection_t *conn);
static void command_process_versions_cell(cell_t *cell, or_connection_t *conn);
static void command_process_netinfo_cell(cell_t *cell, or_connection_t *conn);

#ifdef KEEP_TIMING_STATS
/** This is a wrapper function around the actual function that processes the
@@ -99,6 +103,16 @@ command_process_cell(cell_t *cell, or_connection_t *conn)
  }
#endif

#ifdef KEEP_TIMING_STATS
#define PROCESS_CELL(tp, cl, cn) STMT_BEGIN {                   \
    ++num ## tp;                                                \
    command_time_process_cell(cl, cn, & tp ## time ,            \
                              command_process_ ## tp ## _cell);  \
  } STMT_END
#else
#define PROCESS_CELL(tp, cl, cn) command_process_ ## tp ## _cell(cl, cn)
#endif

  switch (cell->command) {
    case CELL_PADDING:
      ++stats_n_padding_cells_processed;
@@ -107,47 +121,31 @@ command_process_cell(cell_t *cell, or_connection_t *conn)
    case CELL_CREATE:
    case CELL_CREATE_FAST:
      ++stats_n_create_cells_processed;
#ifdef KEEP_TIMING_STATS
      ++num_create;
      command_time_process_cell(cell, conn, &create_time,
                                command_process_create_cell);
#else
      command_process_create_cell(cell, conn);
#endif
      PROCESS_CELL(create, cell, conn);
      break;
    case CELL_CREATED:
    case CELL_CREATED_FAST:
      ++stats_n_created_cells_processed;
#ifdef KEEP_TIMING_STATS
      ++num_created;
      command_time_process_cell(cell, conn, &created_time,
                                command_process_created_cell);
#else
      command_process_created_cell(cell, conn);
#endif
      PROCESS_CELL(created, cell, conn);
      break;
    case CELL_RELAY:
      ++stats_n_relay_cells_processed;
#ifdef KEEP_TIMING_STATS
      ++num_relay;
      command_time_process_cell(cell, conn, &relay_time,
                                command_process_relay_cell);
#else
      command_process_relay_cell(cell, conn);
#endif
      PROCESS_CELL(relay, cell, conn);
      break;
    case CELL_DESTROY:
      ++stats_n_destroy_cells_processed;
#ifdef KEEP_TIMING_STATS
      ++num_destroy;
      command_time_process_cell(cell, conn, &destroy_time,
                                command_process_destroy_cell);
#else
      command_process_destroy_cell(cell, conn);
#endif
      PROCESS_CELL(destroy, cell, conn);
      break;
    case CELL_VERSIONS:
      ++stats_n_versions_cells_processed;
      PROCESS_CELL(versions, cell, conn);
      break;
    case CELL_NETINFO:
      ++stats_n_netinfo_cells_processed;
      PROCESS_CELL(netinfo, cell, conn);
      break;
    default:
      log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
      log_fn(LOG_INFO, LD_PROTOCOL,
             "Cell of unknown type (%d) received. Dropping.", cell->command);
      break;
  }
@@ -389,3 +387,110 @@ command_process_destroy_cell(cell_t *cell, or_connection_t *conn)
  }
}

/** Process a 'versions' cell.  The current link protocol version must be 0
 * to indicate that no version has yet been negotiated. DOCDOC say more. */
static void
command_process_versions_cell(cell_t *cell, or_connection_t *conn)
{
  uint16_t versionslen;
  int highest_supported_version = 0;
  const char *cp, *end;
  if (conn->link_proto != 0) {
    log_fn(LOG_PROTOCOL_WARN, LD_OR,
           "Received a VERSIONS cell on a connection with its version "
           "already set to %d; dropping", (int) conn->link_proto);
    return;
  }
  versionslen = ntohs(get_uint16(cell->payload));
  end = cell->payload + 2 + versionslen;
  if (end > cell->payload + CELL_PAYLOAD_SIZE)
    end = cell->payload + CELL_PAYLOAD_SIZE; /*XXXX020 warn?*/
  for (cp = cell->payload + 2; cp < end; ++cp) {
    uint8_t v = *cp;
    if (v == 1) {
      if (v > highest_supported_version)
        highest_supported_version = v;
    }
  }
  if (!versionslen) {
    log_fn(LOG_PROTOCOL_WARN, LD_OR,
           "Couldn't find a version in common; defaulting to v1.");
    /*XXXX020 or just break the connection?*/
    conn->link_proto = 1;
    return;
  }
}

/** Process a 'netinfo' cell. DOCDOC say more. */
static void
command_process_netinfo_cell(cell_t *cell, or_connection_t *conn)
{
  time_t timestamp;
  uint8_t my_addr_type;
  uint8_t my_addr_len;
  const char *my_addr_ptr;
  const char *cp, *end;
  uint8_t n_other_addrs;
  time_t now = time(NULL);

  /*XXXX020 reject duplicat netinfos. */

  if (conn->link_proto < 2) {
    log_fn(LOG_PROTOCOL_WARN, LD_OR,
           "Received a NETINFO cell on %s connection; dropping.",
           conn->link_proto == 0 ? "non-versioned" : "a v1");
    return;
  }
  /* Decode the cell. */
  timestamp = ntohl(get_uint32(cell->payload));
  my_addr_type = (uint8_t) cell->payload[4];
  my_addr_len = (uint8_t) cell->payload[5];
  my_addr_ptr = cell->payload + 6;
  /* Possibly learn my address. XXXX020 */
  end = cell->payload + CELL_PAYLOAD_SIZE;
  cp = cell->payload + 6 + my_addr_len;
  if (cp >= end) {
    log_fn(LOG_PROTOCOL_WARN, LD_OR,
           "Address too long in netinfo cell; dropping.");
    return;
  }

  /*XXXX020 magic number 3600 */
  if (abs(timestamp - now) > 3600 &&
      router_get_by_digest(conn->identity_digest)) {
    long delta = now - timestamp;
    char dbuf[64];
    /*XXXX020 not always warn!*/
    format_time_interval(dbuf, sizeof(dbuf), delta);
    log_fn(LOG_WARN, LD_HTTP, "Received NETINFO cell with skewed time from "
           "server at %s:%d.  It seems that our clock is %s by %s, or "
           "that theirs is %s. Tor requires an accurate clock to work: "
           "please check your time and date settings.",
           conn->_base.address, (int)conn->_base.port,
           delta>0 ? "ahead" : "behind", dbuf,
           delta>0 ? "behind" : "ahead");
    control_event_general_status(LOG_WARN,
                                 "CLOCK_SKEW SKEW=%ld SOURCE=OR:%s:%d",
                                 delta, conn->_base.address, conn->_base.port);
  }

  n_other_addrs = (uint8_t) *cp++;
  while (n_other_addrs && cp < end-2) {
    /* Consider all the other addresses; if any matches, this connection is
     * "canonical." */
    uint8_t other_addr_type = (uint8_t) *cp++;
    uint8_t other_addr_len = (uint8_t) *cp++;
    if (cp + other_addr_len >= end)
      break; /*XXXX020 protocol warn. */
    if (other_addr_type == RESOLVED_TYPE_IPV4 && other_addr_len == 4) {
      uint32_t addr = ntohl(get_uint32(cp));
      if (addr == conn->real_addr) {
        conn->is_canonical = 1;
        break;
      }
    }
    cp += other_addr_len;
    --n_other_addrs;
  }
}
+60 −0
Changes for src/or/connection_or.c: 60 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -356,11 +356,16 @@ connection_or_init_conn_from_address(or_connection_t *conn,
  connection_or_set_identity_digest(conn, id_digest);
  conn->_base.addr = addr;
  conn->_base.port = port;
  conn->real_addr = addr;
  if (r) {
    if (conn->_base.addr == r->addr)
      conn->is_canonical = 1;
    if (!started_here) {
      /* Override the addr/port, so our log messages will make sense.
       * This is dangerous, since if we ever try looking up a conn by
       * its actual addr/port, we won't remember. Careful! */
      /* XXXX020 this is stupid, and it's the reason we need real_addr to
       * track is_canonical properly. */
      conn->_base.addr = r->addr;
      conn->_base.port = r->or_port;
    }
@@ -740,6 +745,8 @@ connection_tls_finish_handshake(or_connection_t *conn)
  }
  connection_watch_events(TO_CONN(conn), EV_READ);
  circuit_n_conn_done(conn, 1); /* send the pending creates, if any. */

  conn->link_proto = 1; /* Version negotiation not yet enabled.XXX020 */
  return 0;
}

@@ -825,3 +832,56 @@ connection_or_send_destroy(uint16_t circ_id, or_connection_t *conn, int reason)
  return 0;
}

/** DOCDOC */
static int
connection_or_send_versions(or_connection_t *conn)
{
  cell_t cell;
  uint8_t versions[] = { 1 };
  int n_versions = sizeof(versions) / sizeof(uint8_t);
  int i;
  memset(&cell, 0, sizeof(cell_t));
  cell.command = CELL_VERSIONS;
  set_uint16(cell.payload, htons(n_versions));
  for (i = 0; i < n_versions; ++i) {
    uint8_t v = versions[i];
    tor_assert(v > 0 && v < 128);
    cell.payload[2+i] = v;
  }

  connection_or_write_cell_to_buf(&cell, conn);
}

/** DOCDOC */
static int
connection_or_send_netinfo(or_connection_t *conn)
{
  cell_t cell;
  time_t now = time(NULL);
  routerinfo_t *me;

  memset(&cell, 0, sizeof(cell_t));
  cell.command = CELL_NETINFO;

  /* Their address. */
  set_uint32(cell.payload, htonl(now));
  cell.payload[4] = RESOLVED_TYPE_IPV4;
  cell.payload[5] = 4;
  set_uint32(cell.payload+6, htonl(conn->_base.addr));

  /* My address. */
  if ((me = router_get_my_routerinfo())) {
    cell.payload[10] = 1; /* only one address is supported. */
    cell.payload[11] = RESOLVED_TYPE_IPV4;
    cell.payload[12] = 4;
    set_uint32(cell.payload+13, htonl(me->addr));
  } else {
    cell.payload[10] = 0;
  }

  connection_or_write_cell_to_buf(&cell, conn);

  /*XXXX020 remove these once we send netinfo and versions cells. */
  (void) connection_or_send_netinfo;
  (void) connection_or_send_versions;
}
+7 −0
Changes for src/or/or.h: 7 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -651,6 +651,8 @@ typedef enum {
#define CELL_DESTROY 4
#define CELL_CREATE_FAST 5
#define CELL_CREATED_FAST 6
#define CELL_VERSIONS 7
#define CELL_NETINFO 8

/** How long to test reachability before complaining to the user. */
#define TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT (20*60)
@@ -868,9 +870,14 @@ typedef struct or_connection_t {
   * recent, we can rate limit it further. */
  time_t client_used;

  uint32_t real_addr; /**DOCDOC */

  circ_id_type_t circ_id_type:2; /**< When we send CREATE cells along this
                                  * connection, which half of the space should
                                  * we use? */
  unsigned int is_canonical; /**< DOCDOC */
  uint8_t link_proto; /**< What protocol version are we using? 0 for
                       * "none negotiated yet." */
  uint16_t next_circ_id; /**< Which circ_id do we try to use next on
                          * this connection?  This is always in the
                          * range 0..1<<15-1. */
Loading