diff --git a/src/or/connection_or.c b/src/or/connection_or.c index 976889ad0a..267463312c 100644 --- a/src/or/connection_or.c +++ b/src/or/connection_or.c @@ -28,6 +28,7 @@ * part of a subclass (channel_tls_t). */ #define TOR_CHANNEL_INTERNAL_ +#define CONNECTION_OR_PRIVATE #include "channel.h" #include "channeltls.h" #include "circuitbuild.h" @@ -1255,7 +1256,7 @@ or_connect_failure_find(const or_connection_t *or_conn) /* Note down in the connection failure cache that a failure occurred on the * given or_conn. */ -static void +STATIC void note_or_connect_failed(const or_connection_t *or_conn) { or_connect_failure_entry_t *ocf = NULL; @@ -1294,7 +1295,7 @@ or_connect_failure_map_cleanup(time_t cutoff) * * The or_conn MUST have gone through connection_or_check_canonicity() so the * base address is properly set to what we know or doesn't know. */ -static int +STATIC int should_connect_to_relay(const or_connection_t *or_conn) { time_t now, cutoff; diff --git a/src/or/connection_or.h b/src/or/connection_or.h index 7c1dced631..158eb1fdad 100644 --- a/src/or/connection_or.h +++ b/src/or/connection_or.h @@ -120,6 +120,11 @@ int connection_or_single_set_badness_(time_t now, int force); void connection_or_group_set_badness_(smartlist_t *group, int force); +#ifdef CONNECTION_OR_PRIVATE +STATIC int should_connect_to_relay(const or_connection_t *or_conn); +STATIC void note_or_connect_failed(const or_connection_t *or_conn); +#endif + #ifdef TOR_UNIT_TESTS extern int certs_cell_ed25519_disabled_for_testing; #endif diff --git a/src/or/nodelist.c b/src/or/nodelist.c index 391b31d683..7303539c87 100644 --- a/src/or/nodelist.c +++ b/src/or/nodelist.c @@ -161,8 +161,8 @@ init_nodelist(void) } /** As node_get_by_id, but returns a non-const pointer */ -node_t * -node_get_mutable_by_id(const char *identity_digest) +MOCK_IMPL(node_t *, +node_get_mutable_by_id,(const char *identity_digest)) { node_t search, *node; if (PREDICT_UNLIKELY(the_nodelist == NULL)) diff --git a/src/or/nodelist.h b/src/or/nodelist.h index dc20eaf0a5..043d7b3414 100644 --- a/src/or/nodelist.h +++ b/src/or/nodelist.h @@ -16,7 +16,7 @@ tor_assert((n)->ri || (n)->rs); \ } STMT_END -node_t *node_get_mutable_by_id(const char *identity_digest); +MOCK_DECL(node_t *, node_get_mutable_by_id,(const char *identity_digest)); MOCK_DECL(const node_t *, node_get_by_id, (const char *identity_digest)); node_t *node_get_mutable_by_ed25519_id(const ed25519_public_key_t *ed_id); MOCK_DECL(const node_t *, node_get_by_ed25519_id, diff --git a/src/test/test_connection.c b/src/test/test_connection.c index 33f453b8b2..dc0f6860d9 100644 --- a/src/test/test_connection.c +++ b/src/test/test_connection.c @@ -5,6 +5,7 @@ #define CONNECTION_PRIVATE #define MAIN_PRIVATE +#define CONNECTION_OR_PRIVATE #include "or.h" #include "test.h" @@ -13,9 +14,11 @@ #include "hs_common.h" #include "main.h" #include "microdesc.h" +#include "nodelist.h" #include "networkstatus.h" #include "rendcache.h" #include "directory.h" +#include "connection_or.h" #include "test_connection.h" #include "test_helpers.h" @@ -776,6 +779,99 @@ test_conn_download_status(void *arg) /* the teardown function removes all the connections in the global list*/; } +static node_t test_node; + +static node_t * +mock_node_get_mutable_by_id(const char *digest) +{ + (void) digest; + static routerinfo_t node_ri; + memset(&node_ri, 0, sizeof(node_ri)); + + test_node.ri = &node_ri; + memset(test_node.identity, 'c', sizeof(test_node.identity)); + + tor_addr_t ipv4_addr; + tor_addr_parse(&ipv4_addr, "18.0.0.1"); + node_ri.addr = tor_addr_to_ipv4h(&ipv4_addr); + node_ri.or_port = 1; + + return &test_node; +} + +static const node_t * +mock_node_get_by_id(const char *digest) +{ + (void) digest; + memset(test_node.identity, 'c', sizeof(test_node.identity)); + return &test_node; +} + +/* Test whether we correctly track failed connections between relays. */ +static void +test_failed_orconn_tracker(void *arg) +{ + (void) arg; + + int can_connect; + time_t now = 1281533250; /* 2010-08-11 13:27:30 UTC */ + (void) now; + + update_approx_time(now); + + /* Prepare the OR connection that will be used in this test */ + or_connection_t or_conn; + tt_int_op(AF_INET,OP_EQ, tor_addr_parse(&or_conn.real_addr, "18.0.0.1")); + tt_int_op(AF_INET,OP_EQ, tor_addr_parse(&or_conn.base_.addr, "18.0.0.1")); + or_conn.base_.port = 1; + memset(or_conn.identity_digest, 'c', sizeof(or_conn.identity_digest)); + + /* Check whether we can connect with an empty failure cache: + * this should succeed */ + can_connect = should_connect_to_relay(&or_conn); + tt_int_op(can_connect, OP_EQ, 1); + + /* Now add the destination to the failure cache */ + note_or_connect_failed(&or_conn); + + /* Check again: now it shouldn't connect */ + can_connect = should_connect_to_relay(&or_conn); + tt_int_op(can_connect, OP_EQ, 0); + + /* Move time forward and check again: the cache should have been cleared and + * now it should connect */ + now += 3600; + update_approx_time(now); + can_connect = should_connect_to_relay(&or_conn); + tt_int_op(can_connect, OP_EQ, 1); + + /* Now mock the node_get_*by_id() functions to start using the node subsystem + * optimization. */ + MOCK(node_get_by_id, mock_node_get_by_id); + MOCK(node_get_mutable_by_id, mock_node_get_mutable_by_id); + + /* Since we just started using the node subsystem it will allow connections + * now */ + can_connect = should_connect_to_relay(&or_conn); + tt_int_op(can_connect, OP_EQ, 1); + + /* Mark it as failed */ + note_or_connect_failed(&or_conn); + + /* Check that it shouldn't connect now */ + can_connect = should_connect_to_relay(&or_conn); + tt_int_op(can_connect, OP_EQ, 0); + + /* Move time forward and check again: now it should connect */ + now += 3600; + update_approx_time(now); + can_connect = should_connect_to_relay(&or_conn); + tt_int_op(can_connect, OP_EQ, 1); + + done: + ; +} + #define CONNECTION_TESTCASE(name, fork, setup) \ { #name, test_conn_##name, fork, &setup, NULL } @@ -792,6 +888,7 @@ struct testcase_t connection_tests[] = { CONNECTION_TESTCASE_ARG(download_status, TT_FORK, test_conn_download_status_st, FLAV_NS), //CONNECTION_TESTCASE(func_suffix, TT_FORK, setup_func_pair), + { "failed_orconn_tracker", test_failed_orconn_tracker, TT_FORK, NULL, NULL }, END_OF_TESTCASES };