diff options
-rw-r--r-- | src/or/connection_or.c | 41 | ||||
-rw-r--r-- | src/test/test_link_handshake.c | 4 |
2 files changed, 44 insertions, 1 deletions
diff --git a/src/or/connection_or.c b/src/or/connection_or.c index 953e9df251..088900ccec 100644 --- a/src/or/connection_or.c +++ b/src/or/connection_or.c @@ -75,6 +75,9 @@ static void connection_or_mark_bad_for_new_circs(or_connection_t *or_conn); static void connection_or_change_state(or_connection_t *conn, uint8_t state); +static void connection_or_check_canonicity(or_connection_t *conn, + int started_here); + /**************************************************************/ /** Global map between Extended ORPort identifiers and OR @@ -869,13 +872,38 @@ connection_or_init_conn_from_address(or_connection_t *conn, ed25519_fmt(ed_id), started_here); - const node_t *r = node_get_by_id(id_digest); connection_or_set_identity_digest(conn, id_digest, ed_id); connection_or_update_token_buckets_helper(conn, 1, get_options()); conn->base_.port = port; tor_addr_copy(&conn->base_.addr, addr); tor_addr_copy(&conn->real_addr, addr); + + connection_or_check_canonicity(conn, started_here); +} + +/** Check whether the identity of <b>conn</b> matches a known node. If it + * does, check whether the address of conn matches the expected address, and + * update the connection's is_canonical flag, nickname, and address fields as + * appropriate. */ +static void +connection_or_check_canonicity(or_connection_t *conn, int started_here) +{ + const char *id_digest = conn->identity_digest; + const ed25519_public_key_t *ed_id = NULL; + const tor_addr_t *addr = &conn->real_addr; + if (conn->chan) + ed_id = & TLS_CHAN_TO_BASE(conn->chan)->ed25519_identity; + + const node_t *r = node_get_by_id(id_digest); + if (r && + node_supports_ed25519_link_authentication(r) && + ! node_ed25519_id_matches(r, ed_id)) { + /* If this node is capable of proving an ed25519 ID, + * we can't call this a canonical connection unless both IDs match. */ + r = NULL; + } + if (r) { tor_addr_port_t node_ap; node_get_pref_orport(r, &node_ap); @@ -897,10 +925,12 @@ connection_or_init_conn_from_address(or_connection_t *conn, tor_addr_copy(&conn->base_.addr, &node_ap.addr); conn->base_.port = node_ap.port; } + tor_free(conn->nickname); conn->nickname = tor_strdup(node_get_nickname(r)); tor_free(conn->base_.address); conn->base_.address = tor_addr_to_str_dup(&node_ap.addr); } else { + tor_free(conn->nickname); conn->nickname = tor_malloc(HEX_DIGEST_LEN+2); conn->nickname[0] = '$'; base16_encode(conn->nickname+1, HEX_DIGEST_LEN+1, @@ -1589,6 +1619,7 @@ connection_or_client_learned_peer_id(or_connection_t *conn, const or_options_t *options = get_options(); channel_tls_t *chan_tls = conn->chan; channel_t *chan = channel_tls_to_base(chan_tls); + int changed_identity = 0; tor_assert(chan); const int expected_rsa_key = @@ -1619,6 +1650,7 @@ connection_or_client_learned_peer_id(or_connection_t *conn, * we do -- remember it for future attempts. */ learned_router_identity(&conn->base_.addr, conn->base_.port, (const char*)rsa_peer_id, ed_peer_id); + changed_identity = 1; } const int rsa_mismatch = expected_rsa_key && @@ -1706,6 +1738,13 @@ connection_or_client_learned_peer_id(or_connection_t *conn, "connection."); connection_or_set_identity_digest(conn, (const char*)rsa_peer_id, ed_peer_id); + changed_identity = 1; + } + + if (changed_identity) { + /* If we learned an identity for this connection, then we might have + * just discovered it to be canonical. */ + connection_or_check_canonicity(conn, conn->handshake_state->started_here); } if (authdir_mode_tests_reachability(options)) { diff --git a/src/test/test_link_handshake.c b/src/test/test_link_handshake.c index 9931702a34..421f3aaedf 100644 --- a/src/test/test_link_handshake.c +++ b/src/test/test_link_handshake.c @@ -117,6 +117,9 @@ test_link_handshake_certs_ok(void *arg) crypto_pk_t *key1 = NULL, *key2 = NULL; const int with_ed = !strcmp((const char *)arg, "Ed25519"); + tor_addr_from_ipv4h(&c1->base_.addr, 0x7f000001); + tor_addr_from_ipv4h(&c2->base_.addr, 0x7f000001); + scheduler_init(); MOCK(tor_tls_cert_matches_key, mock_tls_cert_matches_key); @@ -354,6 +357,7 @@ recv_certs_setup(const struct testcase_t *test) d->chan = tor_malloc_zero(sizeof(*d->chan)); d->c->chan = d->chan; d->c->base_.address = tor_strdup("HaveAnAddress"); + tor_addr_from_ipv4h(&d->c->base_.addr, 0x801f0127); d->c->base_.state = OR_CONN_STATE_OR_HANDSHAKING_V3; d->chan->conn = d->c; tt_int_op(connection_init_or_handshake_state(d->c, 1), ==, 0); |