aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/TODO17
-rw-r--r--doc/spec/proposals/105-handshake-revision.txt7
-rw-r--r--src/or/command.c165
-rw-r--r--src/or/connection_or.c62
-rw-r--r--src/or/or.h7
-rw-r--r--src/or/router.c1
6 files changed, 220 insertions, 39 deletions
diff --git a/doc/TODO b/doc/TODO
index 60bf7bf70..30087cbdf 100644
--- a/doc/TODO
+++ b/doc/TODO
@@ -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.
diff --git a/doc/spec/proposals/105-handshake-revision.txt b/doc/spec/proposals/105-handshake-revision.txt
index f9a8bfe1a..634c1c50d 100644
--- a/doc/spec/proposals/105-handshake-revision.txt
+++ b/doc/spec/proposals/105-handshake-revision.txt
@@ -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
diff --git a/src/or/command.c b/src/or/command.c
index d89581216..4fa098d9a 100644
--- a/src/or/command.c
+++ b/src/or/command.c
@@ -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;
+ }
+}
+
diff --git a/src/or/connection_or.c b/src/or/connection_or.c
index 6b4c9e663..1d083e39b 100644
--- a/src/or/connection_or.c
+++ b/src/or/connection_or.c
@@ -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;
}
@@ -773,7 +780,7 @@ connection_or_process_cells_from_inbuf(or_connection_t *conn)
char buf[CELL_NETWORK_SIZE];
cell_t cell;
-loop:
+ loop:
log_debug(LD_OR,
"%d: starting, inbuf_datalen %d (%d pending in tls object).",
conn->_base.s,(int)buf_datalen(conn->_base.inbuf),
@@ -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;
+}
diff --git a/src/or/or.h b/src/or/or.h
index de2c74268..20766ac3c 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -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. */
diff --git a/src/or/router.c b/src/or/router.c
index c7bf5efa1..6a80e393d 100644
--- a/src/or/router.c
+++ b/src/or/router.c
@@ -1570,6 +1570,7 @@ router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router,
result = tor_snprintf(s, maxlen,
"router %s %s %d 0 %d\n"
"platform %s\n"
+ "opt protocols Link 1 Circuit 1\n"
"published %s\n"
"opt fingerprint %s\n"
"uptime %ld\n"