#define GUARDFRACTION_PRIVATE
#define NETWORKSTATUS_PRIVATE
#define NS_PARSE_PRIVATE
#include "orconfig.h"
#include "core/or/or.h"
#include "app/config/config.h"
#include "feature/dirauth/guardfraction.h"
#include "feature/client/entrynodes.h"
#include "feature/dirparse/ns_parse.h"
#include "feature/nodelist/networkstatus.h"
#include "feature/nodelist/networkstatus_st.h"
#include "feature/dirauth/vote_microdesc_hash_st.h"
#include "feature/nodelist/vote_routerstatus_st.h"
#include "test/test.h"
#include "test/test_helpers.h"
#include "test/log_test_helpers.h"
static vote_routerstatus_t *
gen_vote_routerstatus_for_tests(const char *digest_in_hex, int is_guard)
{
int retval;
vote_routerstatus_t *vrs = NULL;
routerstatus_t *rs;
vrs = tor_malloc_zero(sizeof(vote_routerstatus_t));
rs = &vrs->status;
{
char digest_tmp[DIGEST_LEN];
rs->is_possible_guard = is_guard;
tt_int_op(strlen(digest_in_hex), OP_EQ, HEX_DIGEST_LEN);
retval = base16_decode(digest_tmp, sizeof(digest_tmp),
digest_in_hex, HEX_DIGEST_LEN);
tt_int_op(retval, OP_EQ, sizeof(digest_tmp));
memcpy(rs->identity_digest, digest_tmp, DIGEST_LEN);
}
{
vrs->version = tor_strdup("0.1.2.14");
strlcpy(rs->nickname, "router2", sizeof(rs->nickname));
memset(rs->descriptor_digest, 78, DIGEST_LEN);
rs->addr = 0x99008801;
rs->or_port = 443;
rs->dir_port = 8000;
rs->is_flagged_running = 1;
vrs->has_measured_bw = 1;
rs->has_bandwidth = 1;
}
return vrs;
done:
vote_routerstatus_free(vrs);
return NULL;
}
static void
test_parse_guardfraction_file_bad(void *arg)
{
int retval;
char *guardfraction_bad = NULL;
const char *yesterday_date_str = get_yesterday_date_str();
(void) arg;
tor_asprintf(&guardfraction_bad,
"guardfraction-file-version nan\n"
"written-at %s\n"
"n-inputs 420 3\n"
"guard-seen D0EDB47BEAD32D26D0A837F7D5357EC3AD3B8777 100 420\n"
"guard-seen 07B5547026DF3E229806E135CFA8552D56AFBABC 5 420\n",
yesterday_date_str);
retval = dirserv_read_guardfraction_file_from_str(guardfraction_bad, NULL);
tt_int_op(retval, OP_EQ, -1);
tor_free(guardfraction_bad);
tor_asprintf(&guardfraction_bad,
"guardfraction-file-version 1\n"
"written-at not_date\n"
"n-inputs 420 3\n"
"guard-seen D0EDB47BEAD32D26D0A837F7D5357EC3AD3B8777 100 420\n"
"guard-seen 07B5547026DF3E229806E135CFA8552D56AFBABC 5 420\n");
retval = dirserv_read_guardfraction_file_from_str(guardfraction_bad, NULL);
tt_int_op(retval, OP_EQ, -1);
tor_free(guardfraction_bad);
tor_asprintf(&guardfraction_bad,
"guardfraction-file-version 1\n"
"written-at %s\n"
"n-inputs biggie\n"
"guard-seen D0EDB47BEAD32D26D0A837F7D5357EC3AD3B8777 100 420\n"
"guard-seen 07B5547026DF3E229806E135CFA8552D56AFBABC 5 420\n",
yesterday_date_str);
retval = dirserv_read_guardfraction_file_from_str(guardfraction_bad, NULL);
tt_int_op(retval, OP_EQ, 2);
tor_free(guardfraction_bad);
tor_asprintf(&guardfraction_bad,
"guardfraction-file-version 1\n"
"written-at %s\n"
"n-inputs 420 3\n"
"guard-seen not_a_fingerprint 100 420\n",
yesterday_date_str);
retval = dirserv_read_guardfraction_file_from_str(guardfraction_bad, NULL);
tt_int_op(retval, OP_EQ, 0);
tor_free(guardfraction_bad);
tor_asprintf(&guardfraction_bad,
"guardfraction-file-version 1\n"
"written-at %s\n"
"n-inputs 420 3\n"
"guard-seen D0EDB47BEAD32D26D0A837F7D5357EC3AD3B8777 NaN 420\n"
"guard-seen 07B5547026DF3E229806E135CFA8552D56AFBABC 5 420\n",
yesterday_date_str);
retval = dirserv_read_guardfraction_file_from_str(guardfraction_bad, NULL);
tt_int_op(retval, OP_EQ, 1);
tor_free(guardfraction_bad);
tor_asprintf(&guardfraction_bad,
"guardfraction-file-version 1\n"
"written-at %s\n"
"n-inputs 420 3\n"
"guard-seen D0EDB47BEAD32D26D0A837F7D5357EC3AD3B8777 666 420\n"
"guard-seen 07B5547026DF3E229806E135CFA8552D56AFBABC 5 420\n",
yesterday_date_str);
retval = dirserv_read_guardfraction_file_from_str(guardfraction_bad, NULL);
tt_int_op(retval, OP_EQ, 1);
tor_free(guardfraction_bad);
tor_asprintf(&guardfraction_bad,
"guardfraction-file-version 1\n"
"written-at %s\n"
"n-inputs 420 3\n"
"guard-seen D0EDB47BEAD32D26D0A837F7D5357EC3AD3B8777 -3 420\n",
yesterday_date_str);
retval = dirserv_read_guardfraction_file_from_str(guardfraction_bad, NULL);
tt_int_op(retval, OP_EQ, 0);
done:
tor_free(guardfraction_bad);
}
static void
test_parse_guardfraction_file_good(void *arg)
{
int retval;
vote_routerstatus_t *vrs_guard = NULL;
vote_routerstatus_t *vrs_dummy = NULL;
char *guardfraction_good = NULL;
const char *yesterday_date_str = get_yesterday_date_str();
smartlist_t *routerstatuses = smartlist_new();
const char fpr_guard[] = "D0EDB47BEAD32D26D0A837F7D5357EC3AD3B8777";
const char fpr_unlisted[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
const int guardfraction_value = 42;
(void) arg;
{
vrs_guard = gen_vote_routerstatus_for_tests(fpr_guard, 1);
tt_assert(vrs_guard);
smartlist_add(routerstatuses, vrs_guard);
vrs_dummy = gen_vote_routerstatus_for_tests(fpr_unlisted, 1);
tt_assert(vrs_dummy);
smartlist_add(routerstatuses, vrs_dummy);
}
tor_asprintf(&guardfraction_good,
"guardfraction-file-version 1\n"
"written-at %s\n"
"n-inputs 420 3\n"
"guard-seen %s %d 420\n",
yesterday_date_str,
fpr_guard, guardfraction_value);
retval = dirserv_read_guardfraction_file_from_str(guardfraction_good,
routerstatuses);
tt_int_op(retval, OP_EQ, 1);
{
tt_assert(vrs_guard->status.has_guardfraction);
tt_int_op(vrs_guard->status.guardfraction_percentage,
OP_EQ,
guardfraction_value);
tt_assert(!vrs_dummy->status.has_guardfraction);
}
done:
vote_routerstatus_free(vrs_guard);
vote_routerstatus_free(vrs_dummy);
smartlist_free(routerstatuses);
tor_free(guardfraction_good);
}
static void
test_get_guardfraction_bandwidth(void *arg)
{
guardfraction_bandwidth_t gf_bw;
const int orig_bw = 1000;
(void) arg;
guard_get_guardfraction_bandwidth(&gf_bw,
orig_bw, 25);
tt_int_op(gf_bw.guard_bw, OP_EQ, 250);
tt_int_op(gf_bw.non_guard_bw, OP_EQ, 750);
tt_int_op(gf_bw.non_guard_bw + gf_bw.guard_bw, OP_EQ, orig_bw);
done:
;
}
static void
test_parse_guardfraction_consensus(void *arg)
{
int retval;
or_options_t *options = get_options_mutable();
const char *guardfraction_str_good = "GuardFraction=66";
routerstatus_t rs_good;
routerstatus_t rs_no_guard;
const char *guardfraction_str_bad1 = "GuardFraction=";
routerstatus_t rs_bad1;
const char *guardfraction_str_bad2 = "GuardFraction=166";
routerstatus_t rs_bad2;
(void) arg;
options->UseGuardFraction = 1;
{
memset(&rs_good, 0, sizeof(routerstatus_t));
rs_good.is_possible_guard = 1;
retval = routerstatus_parse_guardfraction(guardfraction_str_good,
NULL, NULL,
&rs_good);
tt_int_op(retval, OP_EQ, 0);
tt_assert(rs_good.has_guardfraction);
tt_int_op(rs_good.guardfraction_percentage, OP_EQ, 66);
}
{
memset(&rs_no_guard, 0, sizeof(routerstatus_t));
tt_assert(!rs_no_guard.is_possible_guard);
setup_full_capture_of_logs(LOG_WARN);
retval = routerstatus_parse_guardfraction(guardfraction_str_good,
NULL, NULL,
&rs_no_guard);
tt_int_op(retval, OP_EQ, 0);
tt_assert(!rs_no_guard.has_guardfraction);
expect_single_log_msg_containing("Got GuardFraction for non-guard . "
"This is not supposed to happen.");
teardown_capture_of_logs();
}
{
memset(&rs_bad1, 0, sizeof(routerstatus_t));
rs_bad1.is_possible_guard = 1;
retval = routerstatus_parse_guardfraction(guardfraction_str_bad1,
NULL, NULL,
&rs_bad1);
tt_int_op(retval, OP_EQ, -1);
tt_assert(!rs_bad1.has_guardfraction);
}
{
memset(&rs_bad2, 0, sizeof(routerstatus_t));
rs_bad2.is_possible_guard = 1;
retval = routerstatus_parse_guardfraction(guardfraction_str_bad2,
NULL, NULL,
&rs_bad2);
tt_int_op(retval, OP_EQ, -1);
tt_assert(!rs_bad2.has_guardfraction);
}
done:
teardown_capture_of_logs();
}
static void
test_should_apply_guardfraction(void *arg)
{
networkstatus_t vote_enabled, vote_disabled, vote_missing;
or_options_t *options = get_options_mutable();
(void) arg;
{
memset(&vote_enabled, 0, sizeof(vote_enabled));
vote_enabled.net_params = smartlist_new();
smartlist_split_string(vote_enabled.net_params,
"UseGuardFraction=1", NULL, 0, 0);
memset(&vote_disabled, 0, sizeof(vote_disabled));
vote_disabled.net_params = smartlist_new();
smartlist_split_string(vote_disabled.net_params,
"UseGuardFraction=0", NULL, 0, 0);
memset(&vote_missing, 0, sizeof(vote_missing));
vote_missing.net_params = smartlist_new();
smartlist_split_string(vote_missing.net_params,
"leon=trout", NULL, 0, 0);
}
options->UseGuardFraction = 1;
tt_int_op(should_apply_guardfraction(&vote_disabled), OP_EQ, 1);
options->UseGuardFraction = 0;
tt_int_op(should_apply_guardfraction(&vote_enabled), OP_EQ, 0);
options->UseGuardFraction = -1;
tt_int_op(should_apply_guardfraction(&vote_enabled), OP_EQ, 1);
tt_int_op(should_apply_guardfraction(&vote_disabled), OP_EQ, 0);
tt_int_op(should_apply_guardfraction(&vote_missing), OP_EQ, 0);
done:
SMARTLIST_FOREACH(vote_enabled.net_params, char *, cp, tor_free(cp));
SMARTLIST_FOREACH(vote_disabled.net_params, char *, cp, tor_free(cp));
SMARTLIST_FOREACH(vote_missing.net_params, char *, cp, tor_free(cp));
smartlist_free(vote_enabled.net_params);
smartlist_free(vote_disabled.net_params);
smartlist_free(vote_missing.net_params);
}
struct testcase_t guardfraction_tests[] = {
{ "parse_guardfraction_file_bad", test_parse_guardfraction_file_bad,
TT_FORK, NULL, NULL },
{ "parse_guardfraction_file_good", test_parse_guardfraction_file_good,
TT_FORK, NULL, NULL },
{ "parse_guardfraction_consensus", test_parse_guardfraction_consensus,
TT_FORK, NULL, NULL },
{ "get_guardfraction_bandwidth", test_get_guardfraction_bandwidth,
TT_FORK, NULL, NULL },
{ "should_apply_guardfraction", test_should_apply_guardfraction,
TT_FORK, NULL, NULL },
END_OF_TESTCASES
};