diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/or/control.c | 92 | ||||
-rw-r--r-- | src/or/control.h | 14 | ||||
-rw-r--r-- | src/or/directory.c | 19 | ||||
-rw-r--r-- | src/or/rendclient.c | 4 | ||||
-rw-r--r-- | src/or/router.c | 23 | ||||
-rw-r--r-- | src/or/router.h | 1 | ||||
-rw-r--r-- | src/test/Makefile.nmake | 3 | ||||
-rw-r--r-- | src/test/include.am | 2 | ||||
-rw-r--r-- | src/test/test.c | 4 | ||||
-rw-r--r-- | src/test/test_hs.c | 115 | ||||
-rw-r--r-- | src/test/test_router.c | 38 |
11 files changed, 308 insertions, 7 deletions
diff --git a/src/or/control.c b/src/or/control.c index 11dd4ee59d..55a2fb779a 100644 --- a/src/or/control.c +++ b/src/or/control.c @@ -940,6 +940,7 @@ static const struct control_event_t control_event_table[] = { { EVENT_TB_EMPTY, "TB_EMPTY" }, { EVENT_CIRC_BANDWIDTH_USED, "CIRC_BW" }, { EVENT_TRANSPORT_LAUNCHED, "TRANSPORT_LAUNCHED" }, + { EVENT_HS_DESC, "HS_DESC" }, { 0, NULL }, }; @@ -1549,7 +1550,7 @@ munge_extrainfo_into_routerinfo(const char *ri_body, outp += router_sig-ri_body; for (i=0; i < 2; ++i) { - const char *kwd = i?"\nwrite-history ":"\nread-history "; + const char *kwd = i ? "\nwrite-history " : "\nread-history "; const char *cp, *eol; if (!(cp = tor_memstr(ei_body, ei_len, kwd))) continue; @@ -4966,6 +4967,95 @@ control_event_transport_launched(const char *mode, const char *transport_name, mode, transport_name, fmt_addr(addr), port); } +/** Convert rendezvous auth type to string for HS_DESC control events + */ +const char * +rend_auth_type_to_string(rend_auth_type_t auth_type) +{ + const char *str; + + switch (auth_type) { + case REND_NO_AUTH: + str = "NO_AUTH"; + break; + case REND_BASIC_AUTH: + str = "BASIC_AUTH"; + break; + case REND_STEALTH_AUTH: + str = "STEALTH_AUTH"; + break; + default: + str = "UNKNOWN"; + } + + return str; +} + +/** send HS_DESC requested event. + * + * <b>rend_query</b> is used to fetch requested onion address and auth type. + * <b>hs_dir</b> is the description of contacting hs directory. + * <b>desc_id_base32</b> is the ID of requested hs descriptor. + */ +void +control_event_hs_descriptor_requested(const rend_data_t *rend_query, + const char *hs_dir, + const char *desc_id_base32) +{ + tor_assert(hs_dir); + send_control_event(EVENT_HS_DESC, ALL_FORMATS, + "650 HS_DESC REQUESTED %s %s %s %s\r\n", + rend_query->onion_address, + rend_auth_type_to_string(rend_query->auth_type), + hs_dir, + desc_id_base32); +} + +/** send HS_DESC event after got response from hs directory. + * + * NOTE: this is an internal function used by following functions: + * control_event_hs_descriptor_received + * control_event_hs_descriptor_failed + * + * So do not call this function directly. + */ +void +control_event_hs_descriptor_receive_end(const char *action, + const rend_data_t *rend_query, + const char *hs_dir) +{ + send_control_event(EVENT_HS_DESC, ALL_FORMATS, + "650 HS_DESC %s %s %s %s\r\n", + action, + rend_query->onion_address, + rend_auth_type_to_string(rend_query->auth_type), + hs_dir); +} + +/** send HS_DESC RECEIVED event + * + * called when a we successfully received a hidden service descriptor. + */ +void +control_event_hs_descriptor_received(const rend_data_t *rend_query, + const char *hs_dir) +{ + tor_assert(hs_dir); + control_event_hs_descriptor_receive_end("RECEIVED", rend_query, hs_dir); +} + +/** send HS_DESC FAILED event + * + * called when request for hidden service descriptor returned failure. + */ +void +control_event_hs_descriptor_failed(const rend_data_t *rend_query, + const char *hs_dir) +{ + tor_assert(hs_dir); + control_event_hs_descriptor_receive_end("FAILED", rend_query, hs_dir); +} + /** Free any leftover allocated memory of the control.c subsystem. */ void control_free_all(void) diff --git a/src/or/control.h b/src/or/control.h index c8db643b7d..be3cc2420e 100644 --- a/src/or/control.h +++ b/src/or/control.h @@ -99,6 +99,17 @@ void control_event_clients_seen(const char *controller_str); void control_event_transport_launched(const char *mode, const char *transport_name, tor_addr_t *addr, uint16_t port); +const char *rend_auth_type_to_string(rend_auth_type_t auth_type); +void control_event_hs_descriptor_requested(const rend_data_t *rend_query, + const char *desc_id_base32, + const char *hs_dir); +void control_event_hs_descriptor_receive_end(const char *action, + const rend_data_t *rend_query, + const char *hs_dir); +void control_event_hs_descriptor_received(const rend_data_t *rend_query, + const char *hs_dir); +void control_event_hs_descriptor_failed(const rend_data_t *rend_query, + const char *hs_dir); void control_free_all(void); @@ -140,7 +151,8 @@ void control_free_all(void); #define EVENT_TB_EMPTY 0x001C #define EVENT_CIRC_BANDWIDTH_USED 0x001D #define EVENT_TRANSPORT_LAUNCHED 0x0020 -#define EVENT_MAX_ 0x0020 +#define EVENT_HS_DESC 0x0021 +#define EVENT_MAX_ 0x0021 /* If EVENT_MAX_ ever hits 0x0040, we need to make the mask into a * different structure. */ diff --git a/src/or/directory.c b/src/or/directory.c index 37a476d1cf..0cacf06617 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -1599,17 +1599,17 @@ connection_dir_client_reached_eof(dir_connection_t *conn) char *body; char *headers; char *reason = NULL; - size_t body_len=0, orig_len=0; + size_t body_len = 0, orig_len = 0; int status_code; - time_t date_header=0; + time_t date_header = 0; long delta; compress_method_t compression; int plausible; - int skewed=0; + int skewed = 0; int allow_partial = (conn->base_.purpose == DIR_PURPOSE_FETCH_SERVERDESC || conn->base_.purpose == DIR_PURPOSE_FETCH_EXTRAINFO || conn->base_.purpose == DIR_PURPOSE_FETCH_MICRODESC); - int was_compressed=0; + int was_compressed = 0; time_t now = time(NULL); int src_code; @@ -2143,6 +2143,10 @@ connection_dir_client_reached_eof(dir_connection_t *conn) } if (conn->base_.purpose == DIR_PURPOSE_FETCH_RENDDESC_V2) { + #define SEND_HS_DESC_FAILED_EVENT() ( \ + control_event_hs_descriptor_failed(conn->rend_data, \ + node_describe_by_id( \ + conn->identity_digest)) ) tor_assert(conn->rend_data); log_info(LD_REND,"Received rendezvous descriptor (size %d, status %d " "(%s))", @@ -2155,6 +2159,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn) "Retrying at another directory."); /* We'll retry when connection_about_to_close_connection() * cleans this dir conn up. */ + SEND_HS_DESC_FAILED_EVENT(); break; case -1: /* We already have a v0 descriptor here. Ignoring this one @@ -2167,6 +2172,9 @@ connection_dir_client_reached_eof(dir_connection_t *conn) /* success. notify pending connections about this. */ log_info(LD_REND, "Successfully fetched v2 rendezvous " "descriptor."); + control_event_hs_descriptor_received(conn->rend_data, + node_describe_by_id( + conn->identity_digest)); conn->base_.purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC; rend_client_desc_trynow(conn->rend_data->onion_address); break; @@ -2177,12 +2185,14 @@ connection_dir_client_reached_eof(dir_connection_t *conn) * connection_about_to_close_connection() cleans this conn up. */ log_info(LD_REND,"Fetching v2 rendezvous descriptor failed: " "Retrying at another directory."); + SEND_HS_DESC_FAILED_EVENT(); break; case 400: log_warn(LD_REND, "Fetching v2 rendezvous descriptor failed: " "http status 400 (%s). Dirserver didn't like our " "v2 rendezvous query? Retrying at another directory.", escaped(reason)); + SEND_HS_DESC_FAILED_EVENT(); break; default: log_warn(LD_REND, "Fetching v2 rendezvous descriptor failed: " @@ -2191,6 +2201,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn) "Retrying at another directory.", status_code, escaped(reason), conn->base_.address, conn->base_.port); + SEND_HS_DESC_FAILED_EVENT(); break; } } diff --git a/src/or/rendclient.c b/src/or/rendclient.c index f00303f189..de28bd1fc5 100644 --- a/src/or/rendclient.c +++ b/src/or/rendclient.c @@ -26,6 +26,7 @@ #include "router.h" #include "routerlist.h" #include "routerset.h" +#include "control.h" static extend_info_t *rend_client_get_random_intro_impl( const rend_cache_entry_t *rend_query, @@ -694,6 +695,9 @@ directory_get_from_hs_dir(const char *desc_id, const rend_data_t *rend_query) (rend_query->auth_type == REND_NO_AUTH ? "[none]" : escaped_safe_str_client(descriptor_cookie_base64)), routerstatus_describe(hs_dir)); + control_event_hs_descriptor_requested(rend_query, + routerstatus_describe(hs_dir), + desc_id_base32); return 1; } diff --git a/src/or/router.c b/src/or/router.c index fd0df52dce..8f56eddef3 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -2916,6 +2916,29 @@ node_describe(const node_t *node) return node_get_description(buf, node); } +/** Return a human-readable description of the node whose identity is + * <b>identity_digest</b>. If node_get_by_id() returns NULL, base 16 encoding + * of <b>identity_digest</b> is returned instead. + * + * This function is not thread-safe. Each call to this function invalidates + * previous values returned by this function. + */ +const char * +node_describe_by_id(const char *identity_digest) +{ + static char buf[NODE_DESC_BUF_LEN]; + const node_t *node = NULL; + + node = node_get_by_id(identity_digest); + if (!node) { + buf[0] = '$'; + base16_encode(buf+1, HEX_DIGEST_LEN+1, identity_digest, DIGEST_LEN); + return buf; + } else { + return node_get_description(buf, node); + } +} + /** Return a human-readable description of the routerstatus_t <b>rs</b>. * * This function is not thread-safe. Each call to this function invalidates diff --git a/src/or/router.h b/src/or/router.h index 1ee0577c8c..a6271c3b3b 100644 --- a/src/or/router.h +++ b/src/or/router.h @@ -132,6 +132,7 @@ const char *routerstatus_get_description(char *buf, const routerstatus_t *rs); const char *extend_info_get_description(char *buf, const extend_info_t *ei); const char *router_describe(const routerinfo_t *ri); const char *node_describe(const node_t *node); +const char *node_describe_by_id(const char *id_digest); const char *routerstatus_describe(const routerstatus_t *ri); const char *extend_info_describe(const extend_info_t *ei); diff --git a/src/test/Makefile.nmake b/src/test/Makefile.nmake index 6479f9d39a..822431f3b8 100644 --- a/src/test/Makefile.nmake +++ b/src/test/Makefile.nmake @@ -14,7 +14,8 @@ LIBS = ..\..\..\build-alpha\lib\libevent.lib \ TEST_OBJECTS = test.obj test_addr.obj test_containers.obj \ test_controller_events.ogj test_crypto.obj test_data.obj test_dir.obj \ test_microdesc.obj test_pt.obj test_util.obj test_config.obj \ - test_cell_formats.obj test_replay.obj test_introduce.obj tinytest.obj + test_cell_formats.obj test_replay.obj test_introduce.obj tinytest.obj \ + test_hs.obj tinytest.obj: ..\ext\tinytest.c $(CC) $(CFLAGS) /D snprintf=_snprintf /c ..\ext\tinytest.c diff --git a/src/test/include.am b/src/test/include.am index c16dd14fe7..b338cbe3e6 100644 --- a/src/test/include.am +++ b/src/test/include.am @@ -38,6 +38,8 @@ src_test_test_SOURCES = \ src/test/test_socks.c \ src/test/test_util.c \ src/test/test_config.c \ + src/test/test_hs.c \ + src/test/test_router.c \ src/ext/tinytest.c src_test_test_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) diff --git a/src/test/test.c b/src/test/test.c index 9b474e9e97..8b2a5ad67d 100644 --- a/src/test/test.c +++ b/src/test/test.c @@ -1625,6 +1625,8 @@ extern struct testcase_t extorport_tests[]; extern struct testcase_t controller_event_tests[]; extern struct testcase_t logging_tests[]; extern struct testcase_t backtrace_tests[]; +extern struct testcase_t hs_tests[]; +extern struct testcase_t router_tests[]; static struct testgroup_t testgroups[] = { { "", test_array }, @@ -1648,6 +1650,8 @@ static struct testgroup_t testgroups[] = { { "options/", options_tests }, { "extorport/", extorport_tests }, { "control/", controller_event_tests }, + { "hs/", hs_tests }, + { "router/", router_tests }, END_OF_GROUPS }; diff --git a/src/test/test_hs.c b/src/test/test_hs.c new file mode 100644 index 0000000000..a9e6644397 --- /dev/null +++ b/src/test/test_hs.c @@ -0,0 +1,115 @@ +/* Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file test_hs.c + * \brief Unit tests for hidden service. + **/ + +#define CONTROL_PRIVATE +#include "or.h" +#include "test.h" +#include "control.h" + +/* Helper global variable for hidden service descriptor event test. + * It's used as a pointer to dynamically created message buffer in + * send_control_event_string_replacement function, which mocks + * send_control_event_string function. + * + * Always free it after use! */ +static char *received_msg = NULL; + +/** Mock function for send_control_event_string + */ +static void +send_control_event_string_replacement(uint16_t event, event_format_t which, + const char *msg) +{ + int msg_len; + + (void) event; + (void) which; + msg_len = strlen(msg); + received_msg = tor_malloc_zero(msg_len+1); + strncpy(received_msg, msg, msg_len); +} + +/** Make sure each hidden service descriptor async event generation + * + * function generates the message in expected format. + */ +static void +test_hs_desc_event(void *arg) +{ + #define STR_HS_ADDR "ajhb7kljbiru65qo" + #define STR_HS_DIR_LONGNAME \ + "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=TestDir at 1.2.3.4" + #define STR_HS_ID "b3oeducbhjmbqmgw2i3jtz4fekkrinwj" + + rend_data_t rend_query; + const char *expected_msg; + + (void) arg; + MOCK(send_control_event_string, + send_control_event_string_replacement); + + /* setup rend_query struct */ + strncpy(rend_query.onion_address, STR_HS_ADDR, + REND_SERVICE_ID_LEN_BASE32+1); + rend_query.auth_type = 0; + + /* test request event */ + control_event_hs_descriptor_requested(&rend_query, STR_HS_DIR_LONGNAME, + STR_HS_ID); + expected_msg = + "650 HS_DESC REQUESTED "STR_HS_ADDR" NO_AUTH "STR_HS_DIR_LONGNAME\ + " "STR_HS_ID"\r\n"; + test_assert(received_msg); + test_streq(received_msg, expected_msg); + tor_free(received_msg); + received_msg = NULL; + + /* test received event */ + rend_query.auth_type = 1; + control_event_hs_descriptor_received(&rend_query, STR_HS_DIR_LONGNAME); + expected_msg = + "650 HS_DESC RECEIVED "STR_HS_ADDR" BASIC_AUTH "STR_HS_DIR_LONGNAME"\r\n"; + test_assert(received_msg); + test_streq(received_msg, expected_msg); + tor_free(received_msg); + received_msg = NULL; + + /* test failed event */ + rend_query.auth_type = 2; + control_event_hs_descriptor_failed(&rend_query, STR_HS_DIR_LONGNAME); + expected_msg = + "650 HS_DESC FAILED "STR_HS_ADDR" STEALTH_AUTH "STR_HS_DIR_LONGNAME"\r\n"; + test_assert(received_msg); + test_streq(received_msg, expected_msg); + tor_free(received_msg); + received_msg = NULL; + + /* test invalid auth type */ + rend_query.auth_type = 999; + control_event_hs_descriptor_failed(&rend_query, STR_HS_DIR_LONGNAME); + expected_msg = + "650 HS_DESC FAILED "STR_HS_ADDR" UNKNOWN "STR_HS_DIR_LONGNAME"\r\n"; + test_assert(received_msg); + test_streq(received_msg, expected_msg); + tor_free(received_msg); + received_msg = NULL; + + done: + UNMOCK(send_control_event_string); + if (received_msg) { + tor_free(received_msg); + received_msg = NULL; + } +} + +struct testcase_t hs_tests[] = { + { "hs_desc_event", test_hs_desc_event, TT_FORK, + NULL, NULL }, + END_OF_TESTCASES +}; + diff --git a/src/test/test_router.c b/src/test/test_router.c new file mode 100644 index 0000000000..c13ccc643e --- /dev/null +++ b/src/test/test_router.c @@ -0,0 +1,38 @@ +/* Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file test_router.c + * \brief Unit tests for router related functions. + **/ + +#include "or.h" +#include "nodelist.h" +#include "router.h" +#include "test.h" + + +/** Tese the case when node_get_by_id() returns NULL, node_describe_by_id + * should return the base 16 encoding of the id. + */ +static void +test_node_describe_by_id_null_node(void *arg) +{ + (void) arg; + + #define ID "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" + + /* make sure node_get_by_id returns NULL */ + test_assert(!node_get_by_id(ID)); + test_streq(node_describe_by_id(ID), + "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); +done: + return; +} + +struct testcase_t router_tests[] = { + { "node_get_by_id_null_node", test_node_describe_by_id_null_node, TT_FORK, + NULL, NULL }, + END_OF_TESTCASES +}; + |