From b2863739083125d332cf1166ae6b095df7d0f155 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 6 Dec 2012 01:53:29 -0500 Subject: [PATCH] Enable the ntor handshake on the client side. "works for me" --- src/or/channeltls.c | 2 + src/or/circuitbuild.c | 103 ++++++++++++++++++++++++++++++++++++++---- src/or/circuitbuild.h | 5 +- src/or/circuituse.c | 4 +- src/or/config.c | 1 + src/or/entrynodes.c | 2 +- src/or/nodelist.c | 12 +++++ src/or/nodelist.h | 1 + src/or/or.h | 5 ++ src/or/relay.c | 4 +- src/or/router.c | 3 +- src/or/routerparse.c | 2 + 12 files changed, 128 insertions(+), 16 deletions(-) diff --git a/src/or/channeltls.c b/src/or/channeltls.c index ede245894e..f6069e0037 100644 --- a/src/or/channeltls.c +++ b/src/or/channeltls.c @@ -914,6 +914,8 @@ channel_tls_handle_cell(cell_t *cell, or_connection_t *conn) case CELL_RELAY: case CELL_RELAY_EARLY: case CELL_DESTROY: + case CELL_CREATE2: + case CELL_CREATED2: /* * These are all transport independent and we pass them up through the * channel_t mechanism. They are ultimately handled in command.c. diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index b7ab47f559..9300b049cb 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -604,6 +604,73 @@ circuit_timeout_want_to_count_circ(origin_circuit_t *circ) && circ->build_state->desired_path_len == DEFAULT_ROUTE_LEN; } +#ifdef CURVE25519_ENABLED +/** Return true if the ntor handshake is enabled in the configuration, or if + * it's been set to "auto" in the configuration and it's enabled in the + * consensus. */ +static int +circuits_can_use_ntor(void) +{ + const or_options_t *options = get_options(); + if (options->UseNTorHandshake != -1) + return options->UseNTorHandshake; + return networkstatus_get_param(NULL, "UseNTorHandshake", 0, 0, 1); +} +#endif + +/** Decide whether to use a TAP or ntor handshake for connecting to ei + * directly, and set *cell_type_out and *handshake_type_out + * accordingly. */ +static void +circuit_pick_create_handshake(uint8_t *cell_type_out, + uint16_t *handshake_type_out, + const extend_info_t *ei) +{ +#ifdef CURVE25519_ENABLED + if (!tor_mem_is_zero((const char*)ei->curve25519_onion_key.public_key, + CURVE25519_PUBKEY_LEN) && + circuits_can_use_ntor()) { + *cell_type_out = CELL_CREATE2; + *handshake_type_out = ONION_HANDSHAKE_TYPE_NTOR; + return; + } +#else + (void) ei; +#endif + + *cell_type_out = CELL_CREATE; + *handshake_type_out = ONION_HANDSHAKE_TYPE_TAP; +} + +/** Decide whether to use a TAP or ntor handshake for connecting to ei + * directly, and set *handshake_type_out accordingly. Decide whether, + * in extending through node to do so, we should use an EXTEND2 or an + * EXTEND cell to do so, and set *cell_type_out and + * *create_cell_type_out accordingly. */ +static void +circuit_pick_extend_handshake(uint8_t *cell_type_out, + uint8_t *create_cell_type_out, + uint16_t *handshake_type_out, + const node_t *node_prev, + const extend_info_t *ei) +{ + uint8_t t; + circuit_pick_create_handshake(&t, handshake_type_out, ei); + /* XXXX024 The check for whether the node has a curve25519 key is a bad + * proxy for whether it can do extend2 cells; once a version that + * handles extend2 cells is out, remove it. */ + if (node_prev && + *handshake_type_out != ONION_HANDSHAKE_TYPE_TAP && + (node_has_curve25519_onion_key(node_prev) || + (node_prev->rs && node_prev->rs->version_supports_extend2_cells))) { + *cell_type_out = RELAY_COMMAND_EXTEND2; + *create_cell_type_out = CELL_CREATE2; + } else { + *cell_type_out = RELAY_COMMAND_EXTEND; + *create_cell_type_out = CELL_CREATE; + } +} + /** This is the backbone function for building circuits. * * If circ's first hop is closed, then we need to build a create @@ -638,10 +705,10 @@ circuit_send_next_onion_skin(origin_circuit_t *circ) fast = should_use_create_fast_for_circuit(circ); if (!fast) { /* We are an OR and we know the right onion key: we should - * send an old slow create cell. + * send a create cell. */ - cc.cell_type = CELL_CREATE; - cc.handshake_type = ONION_HANDSHAKE_TYPE_TAP; + circuit_pick_create_handshake(&cc.cell_type, &cc.handshake_type, + circ->cpath->extend_info); note_request("cell: create", 1); } else { /* We are not an OR, and we're building the first hop of a circuit to a @@ -747,15 +814,21 @@ circuit_send_next_onion_skin(origin_circuit_t *circ) return - END_CIRC_REASON_INTERNAL; } - ec.cell_type = RELAY_COMMAND_EXTEND; + { + const node_t *prev_node; + prev_node = node_get_by_id(hop->prev->extend_info->identity_digest); + circuit_pick_extend_handshake(&ec.cell_type, + &ec.create_cell.cell_type, + &ec.create_cell.handshake_type, + prev_node, + hop->extend_info); + } + 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); - ec.create_cell.handshake_type = ONION_HANDSHAKE_TYPE_TAP; - ec.create_cell.cell_type = CELL_CREATE; - len = onion_skin_create(ec.create_cell.handshake_type, hop->extend_info, &hop->handshake_state, @@ -903,6 +976,7 @@ circuit_extend(cell_t *cell, circuit_t *circ) circ->n_hop = extend_info_new(NULL /*nickname*/, (const char*)ec.node_id, NULL /*onion_key*/, + NULL /*curve25519_key*/, &ec.orport_ipv4.addr, ec.orport_ipv4.port); @@ -938,6 +1012,7 @@ circuit_extend(cell_t *cell, circuit_t *circ) if (circuit_deliver_create_cell(circ, &ec.create_cell, 1) < 0) return -1; + return 0; } @@ -2310,8 +2385,9 @@ onion_append_hop(crypt_path_t **head_ptr, extend_info_t *choice) /** Allocate a new extend_info object based on the various arguments. */ extend_info_t * extend_info_new(const char *nickname, const char *digest, - crypto_pk_t *onion_key, - const tor_addr_t *addr, uint16_t port) + crypto_pk_t *onion_key, + const curve25519_public_key_t *curve25519_key, + const tor_addr_t *addr, uint16_t port) { extend_info_t *info = tor_malloc_zero(sizeof(extend_info_t)); memcpy(info->identity_digest, digest, DIGEST_LEN); @@ -2319,6 +2395,13 @@ extend_info_new(const char *nickname, const char *digest, strlcpy(info->nickname, nickname, sizeof(info->nickname)); if (onion_key) info->onion_key = crypto_pk_dup_key(onion_key); +#ifdef CURVE25519_ENABLED + if (curve25519_key) + memcpy(&info->curve25519_onion_key, curve25519_key, + sizeof(curve25519_public_key_t)); +#else + (void)curve25519_key; +#endif tor_addr_copy(&info->addr, addr); info->port = port; return info; @@ -2353,12 +2436,14 @@ extend_info_from_node(const node_t *node, int for_direct_connect) return extend_info_new(node->ri->nickname, node->identity, node->ri->onion_pkey, + node->ri->onion_curve25519_pkey, &ap.addr, ap.port); else if (node->rs && node->md) return extend_info_new(node->rs->nickname, node->identity, node->md->onion_pkey, + node->md->onion_curve25519_pkey, &ap.addr, ap.port); else diff --git a/src/or/circuitbuild.h b/src/or/circuitbuild.h index 23213e8e83..d4f7926cab 100644 --- a/src/or/circuitbuild.h +++ b/src/or/circuitbuild.h @@ -46,8 +46,9 @@ int circuit_append_new_exit(origin_circuit_t *circ, extend_info_t *info); int circuit_extend_to_new_exit(origin_circuit_t *circ, extend_info_t *info); void onion_append_to_cpath(crypt_path_t **head_ptr, crypt_path_t *new_hop); extend_info_t *extend_info_new(const char *nickname, const char *digest, - crypto_pk_t *onion_key, - const tor_addr_t *addr, uint16_t port); + crypto_pk_t *onion_key, + const curve25519_public_key_t *curve25519_key, + const tor_addr_t *addr, uint16_t port); extend_info_t *extend_info_from_node(const node_t *r, int for_direct_connect); extend_info_t *extend_info_dup(extend_info_t *info); void extend_info_free(extend_info_t *info); diff --git a/src/or/circuituse.c b/src/or/circuituse.c index d3cde1d66c..6a733d6d1a 100644 --- a/src/or/circuituse.c +++ b/src/or/circuituse.c @@ -1577,8 +1577,8 @@ circuit_get_open_circ_or_launch(entry_connection_t *conn, return -1; } extend_info = extend_info_new(conn->chosen_exit_name+1, - digest, NULL, &addr, - conn->socks_request->port); + digest, NULL, NULL, &addr, + conn->socks_request->port); } else { /* We will need an onion key for the router, and we * don't have one. Refuse or relax requirements. */ diff --git a/src/or/config.c b/src/or/config.c index 75f6193352..979d09c7cd 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -383,6 +383,7 @@ static config_var_t option_vars_[] = { V(UseBridges, BOOL, "0"), V(UseEntryGuards, BOOL, "1"), V(UseMicrodescriptors, AUTOBOOL, "auto"), + V(UseNTorHandshake, AUTOBOOL, "auto"), V(User, STRING, NULL), V(UserspaceIOCPBuffers, BOOL, "0"), VAR("V1AuthoritativeDirectory",BOOL, V1AuthoritativeDir, "0"), diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c index edb26dc088..a4e18d04fe 100644 --- a/src/or/entrynodes.c +++ b/src/or/entrynodes.c @@ -1502,7 +1502,7 @@ routerset_contains_bridge(const routerset_t *routerset, return 0; extinfo = extend_info_new( - NULL, bridge->identity, NULL, &bridge->addr, bridge->port); + NULL, bridge->identity, NULL, NULL, &bridge->addr, bridge->port); result = routerset_contains_extendinfo(routerset, extinfo); extend_info_free(extinfo); return result; diff --git a/src/or/nodelist.c b/src/or/nodelist.c index 95345fb262..fa3828fc26 100644 --- a/src/or/nodelist.c +++ b/src/or/nodelist.c @@ -916,6 +916,18 @@ node_get_pref_ipv6_orport(const node_t *node, tor_addr_port_t *ap_out) } } +/** Return true iff node has a curve25519 onion key. */ +int +node_has_curve25519_onion_key(const node_t *node) +{ + if (node->ri) + return node->ri->onion_curve25519_pkey != NULL; + else if (node->md) + return node->md->onion_curve25519_pkey != NULL; + else + return 0; +} + /** Refresh the country code of ri. This function MUST be called on * each router when the GeoIP database is reloaded, and on all new routers. */ void diff --git a/src/or/nodelist.h b/src/or/nodelist.h index 13a3847414..39f0948779 100644 --- a/src/or/nodelist.h +++ b/src/or/nodelist.h @@ -54,6 +54,7 @@ int node_ipv6_preferred(const node_t *node); int node_get_prim_orport(const node_t *node, tor_addr_port_t *ap_out); void node_get_pref_orport(const node_t *node, tor_addr_port_t *ap_out); void node_get_pref_ipv6_orport(const node_t *node, tor_addr_port_t *ap_out); +int node_has_curve25519_onion_key(const node_t *node); smartlist_t *nodelist_get_list(void); diff --git a/src/or/or.h b/src/or/or.h index 66e9054491..b5718a83dc 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -2025,6 +2025,9 @@ typedef struct routerstatus_t { /** True iff this router is a version that allows DATA cells to arrive on * a stream before it has sent a CONNECTED cell. */ unsigned int version_supports_optimistic_data:1; + /** True iff this router has a version that allows it to accept EXTEND2 + * cells */ + unsigned int version_supports_extend2_cells:1; unsigned int has_bandwidth:1; /**< The vote/consensus had bw info */ unsigned int has_exitsummary:1; /**< The vote/consensus had exit summaries */ @@ -3799,6 +3802,8 @@ typedef struct { int IPv6Exit; /**< Do we support exiting to IPv6 addresses? */ + /** Autobool: should we use the ntor handshake if we can? */ + int UseNTorHandshake; } or_options_t; /** Persistent state for an onion router, as saved to disk. */ diff --git a/src/or/relay.c b/src/or/relay.c index 5d87b270f7..ddeec4e789 100644 --- a/src/or/relay.c +++ b/src/or/relay.c @@ -572,6 +572,7 @@ relay_send_command_from_edge(streamid_t stream_id, circuit_t *circ, origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ); if (origin_circ->remaining_relay_early_cells > 0 && (relay_command == RELAY_COMMAND_EXTEND || + relay_command == RELAY_COMMAND_EXTEND2 || cpath_layer != origin_circ->cpath)) { /* If we've got any relay_early cells left and (we're sending * an extend cell or we're not talking to the first hop), use @@ -585,7 +586,8 @@ relay_send_command_from_edge(streamid_t stream_id, circuit_t *circ, * task 878. */ origin_circ->relay_early_commands[ origin_circ->relay_early_cells_sent++] = relay_command; - } else if (relay_command == RELAY_COMMAND_EXTEND) { + } else if (relay_command == RELAY_COMMAND_EXTEND || + relay_command == RELAY_COMMAND_EXTEND2) { /* If no RELAY_EARLY cells can be sent over this circuit, log which * commands have been sent as RELAY_EARLY cells before; helps debug * task 878. */ diff --git a/src/or/router.c b/src/or/router.c index 3733bec4d0..a97db858b0 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -1071,7 +1071,8 @@ extend_info_from_router(const routerinfo_t *r) router_get_prim_orport(r, &ap); return extend_info_new(r->nickname, r->cache_info.identity_digest, - r->onion_pkey, &ap.addr, ap.port); + r->onion_pkey, r->onion_curve25519_pkey, + &ap.addr, ap.port); } /** Some time has passed, or we just got new directory information. diff --git a/src/or/routerparse.c b/src/or/routerparse.c index 17902d9d0a..1be2374062 100644 --- a/src/or/routerparse.c +++ b/src/or/routerparse.c @@ -2188,6 +2188,8 @@ routerstatus_parse_entry_from_string(memarea_t *area, tor_version_supports_microdescriptors(tok->args[0]); rs->version_supports_optimistic_data = tor_version_as_new_as(tok->args[0], "0.2.3.1-alpha"); + rs->version_supports_extend2_cells = + tor_version_as_new_as(tok->args[0], "0.2.4.7-alpha"); } if (vote_rs) { vote_rs->version = tor_strdup(tok->args[0]);