Merge branch 'feature18329_029_squashed' into maint-0.3.2

This commit is contained in:
Nick Mathewson 2017-10-24 19:35:28 -04:00
commit 594cf92498
10 changed files with 273 additions and 1 deletions

9
changes/feature18329 Normal file
View File

@ -0,0 +1,9 @@
o Minor features:
- Bridge relays can now set the BridgeDistribution config option to
add a "bridge-distribution-request" line to their bridge descriptor,
which tells BridgeDB how they'd like their bridge address to be
given out. (Note that as of Oct 2017, BridgeDB does not yet implement
this feature.) As a side benefit, this feature provides a way
to distinguish bridge descriptors from non-bridge descriptors.
Implements tickets 18329.

View File

@ -1670,6 +1670,17 @@ is non-zero):
server descriptor to the bridge database, rather than
to the public directory authorities.
[[BridgeDistribution]] **BridgeDistribution** __string__::
If set along with BridgeRelay, Tor will include a new line in its
bridge descriptor which indicates to the BridgeDB service how it
would like its bridge address to be given out. Set it to "none" if
you want BridgeDB to avoid distributing your bridge address, or "any" to
let BridgeDB decide. (Default: any)
+
Note: as of Oct 2017, the BridgeDB part of this option is not yet
implemented. Until BridgeDB is updated to obey this option, your
bridge will make this request, but it will not (yet) be obeyed.
[[ContactInfo]] **ContactInfo** __email_address__::
Administrative contact information for this relay or bridge. This line
can be used to contact you if your relay or bridge is misconfigured or

View File

@ -253,6 +253,7 @@ static config_var_t option_vars_[] = {
V(BridgePassword, STRING, NULL),
V(BridgeRecordUsageByCountry, BOOL, "1"),
V(BridgeRelay, BOOL, "0"),
V(BridgeDistribution, STRING, NULL),
V(CellStatistics, BOOL, "0"),
V(PaddingStatistics, BOOL, "1"),
V(LearnCircuitBuildTimeout, BOOL, "1"),
@ -731,7 +732,6 @@ static int parse_ports(or_options_t *options, int validate_only,
static int check_server_ports(const smartlist_t *ports,
const or_options_t *options,
int *num_low_ports_out);
static int validate_data_directory(or_options_t *options);
static int write_configuration_file(const char *fname,
const or_options_t *options);
@ -3512,6 +3512,15 @@ options_validate(or_options_t *old_options, or_options_t *options,
REJECT("Relays cannot set ReducedConnectionPadding. ");
}
if (options->BridgeDistribution) {
if (!options->BridgeRelay) {
REJECT("You set BridgeDistribution, but you didn't set BridgeRelay!");
}
if (check_bridge_distribution_setting(options->BridgeDistribution) < 0) {
REJECT("Invalid BridgeDistribution value.");
}
}
if (options->MinUptimeHidServDirectoryV2 < 0) {
log_warn(LD_CONFIG, "MinUptimeHidServDirectoryV2 option must be at "
"least 0 seconds. Changing to 0.");
@ -4686,6 +4695,8 @@ options_transition_affects_descriptor(const or_options_t *old_options,
get_effective_bwburst(old_options) !=
get_effective_bwburst(new_options) ||
!opt_streq(old_options->ContactInfo, new_options->ContactInfo) ||
!opt_streq(old_options->BridgeDistribution,
new_options->BridgeDistribution) ||
!config_lines_eq(old_options->MyFamily, new_options->MyFamily) ||
!opt_streq(old_options->AccountingStart, new_options->AccountingStart) ||
old_options->AccountingMax != new_options->AccountingMax ||
@ -6583,6 +6594,55 @@ warn_client_dns_cache(const char *option, int disabling)
"to your destination.");
}
/**
* Validate the configured bridge distribution method from a BridgeDistribution
* config line.
*
* The input <b>bd</b>, is a string taken from the BridgeDistribution config
* line (if present). If the option wasn't set, return 0 immediately. The
* BridgeDistribution option is then validated. Currently valid, recognised
* options are:
*
* - "none"
* - "any"
* - "https"
* - "email"
* - "moat"
* - "hyphae"
*
* If the option string is unrecognised, a warning will be logged and 0 is
* returned. If the option string contains an invalid character, -1 is
* returned.
**/
STATIC int
check_bridge_distribution_setting(const char *bd)
{
if (bd == NULL)
return 0;
const char *RECOGNIZED[] = {
"none", "any", "https", "email", "moat", "hyphae"
};
unsigned i;
for (i = 0; i < ARRAY_LENGTH(RECOGNIZED); ++i) {
if (!strcmp(bd, RECOGNIZED[i]))
return 0;
}
const char *cp = bd;
// Method = (KeywordChar | "_") +
while (TOR_ISALNUM(*cp) || *cp == '-' || *cp == '_')
++cp;
if (*cp == 0) {
log_warn(LD_CONFIG, "Unrecognized BridgeDistribution value %s. I'll "
"assume you know what you are doing...", escaped(bd));
return 0; // we reached the end of the string; all is well
} else {
return -1; // we found a bad character in the string.
}
}
/**
* Parse port configuration for a single port type.
*

View File

@ -203,6 +203,8 @@ STATIC int parse_port_config(smartlist_t *out,
const char *defaultaddr,
int defaultport,
const unsigned flags);
STATIC int check_bridge_distribution_setting(const char *bd);
#endif /* defined(CONFIG_PRIVATE) */
#endif /* !defined(TOR_CONFIG_H) */

View File

@ -3770,6 +3770,10 @@ typedef struct {
int BridgeAuthoritativeDir; /**< Boolean: is this an authoritative directory
* that aggregates bridge descriptors? */
/** If set on a bridge relay, it will include this value on a new
* "bridge-distribution-request" line in its bridge descriptor. */
char *BridgeDistribution;
/** If set on a bridge authority, it will answer requests on its dirport
* for bridge statuses -- but only if the requests use this password. */
char *BridgePassword;

View File

@ -2956,6 +2956,18 @@ router_dump_router_to_string(routerinfo_t *router,
smartlist_add_asprintf(chunks, "contact %s\n", ci);
}
if (options->BridgeRelay) {
const char *bd;
if (options->BridgeDistribution && strlen(options->BridgeDistribution)) {
bd = options->BridgeDistribution;
} else {
bd = "any";
}
if (strchr(bd, '\n') || strchr(bd, '\r'))
bd = escaped(bd);
smartlist_add_asprintf(chunks, "bridge-distribution-request %s\n", bd);
}
if (router->onion_curve25519_pkey) {
char kbuf[128];
base64_encode(kbuf, sizeof(kbuf),

View File

@ -146,6 +146,7 @@ src_test_test_SOURCES = \
src/test/test_relaycell.c \
src/test/test_rendcache.c \
src/test/test_replay.c \
src/test/test_router.c \
src/test/test_routerkeys.c \
src/test/test_routerlist.c \
src/test/test_routerset.c \

View File

@ -1223,6 +1223,7 @@ struct testgroup_t testgroups[] = {
{ "relaycell/", relaycell_tests },
{ "rend_cache/", rend_cache_tests },
{ "replaycache/", replaycache_tests },
{ "router/", router_tests },
{ "routerkeys/", routerkeys_tests },
{ "routerlist/", routerlist_tests },
{ "routerset/" , routerset_tests },

View File

@ -5446,6 +5446,65 @@ test_config_dup_and_filter(void *arg)
config_free_lines(line_dup);
}
/* If we're not configured to be a bridge, but we set
* BridgeDistribution, then options_validate () should return -1. */
static void
test_config_check_bridge_distribution_setting_not_a_bridge(void *arg) {
or_options_t* options = get_options_mutable();
or_options_t* old_options = options;
or_options_t* default_options = options;
char* message = (char*)("");
int ret;
(void)arg;
options->BridgeRelay = 0;
options->BridgeDistribution = (char*)("https");
ret = options_validate(old_options, options, default_options, 0, &message);
tt_int_op(ret, OP_EQ, -1);
done:
return;
}
/* If the BridgeDistribution setting was valid, 0 should be returned. */
static void
test_config_check_bridge_distribution_setting_valid(void *arg) {
int ret = check_bridge_distribution_setting("https");
(void)arg;
tt_int_op(ret, OP_EQ, 0);
done:
return;
}
/* If the BridgeDistribution setting was invalid, -1 should be returned. */
static void
test_config_check_bridge_distribution_setting_invalid(void *arg) {
int ret = check_bridge_distribution_setting("hyphens-are-not-allowed");
(void)arg;
tt_int_op(ret, OP_EQ, -1);
done:
return;
}
/* If the BridgeDistribution setting was unrecognised, a warning should be
* logged and 0 should be returned. */
static void
test_config_check_bridge_distribution_setting_unrecognised(void *arg) {
int ret = check_bridge_distribution_setting("unicorn");
(void)arg;
tt_int_op(ret, OP_EQ, 0);
done:
return;
}
#define CONFIG_TEST(name, flags) \
{ #name, test_config_ ## name, flags, NULL, NULL }
@ -5489,6 +5548,10 @@ struct testcase_t config_tests[] = {
CONFIG_TEST(include_flag_torrc_only, TT_FORK),
CONFIG_TEST(include_flag_defaults_only, TT_FORK),
CONFIG_TEST(dup_and_filter, 0),
CONFIG_TEST(check_bridge_distribution_setting_not_a_bridge, TT_FORK),
CONFIG_TEST(check_bridge_distribution_setting_valid, 0),
CONFIG_TEST(check_bridge_distribution_setting_invalid, 0),
CONFIG_TEST(check_bridge_distribution_setting_unrecognised, 0),
END_OF_TESTCASES
};

109
src/test/test_router.c Normal file
View File

@ -0,0 +1,109 @@
/* Copyright (c) 2017, The Tor Project, Inc. */
/* Copyright (c) 2017, isis agora lovecruft */
/* See LICENSE for licensing information */
/**
* \file test_router.c
* \brief Unittests for code in src/or/router.c
**/
#include "or.h"
#include "config.h"
#include "crypto_curve25519.h"
#include "crypto_ed25519.h"
#include "router.h"
#include "routerlist.h"
/* Test suite stuff */
#include "test.h"
NS_DECL(const routerinfo_t *, router_get_my_routerinfo, (void));
static routerinfo_t* mock_routerinfo;
static const routerinfo_t*
NS(router_get_my_routerinfo)(void) {
crypto_pk_t* ident_key;
crypto_pk_t* tap_key;
time_t now;
if (!mock_routerinfo) {
/* Mock the published timestamp, otherwise router_dump_router_to_string()
* will poop its pants. */
time(&now);
/* We'll need keys, or router_dump_router_to_string() would return NULL. */
ident_key = pk_generate(0);
tap_key = pk_generate(0);
tor_assert(ident_key != NULL);
tor_assert(tap_key != NULL);
mock_routerinfo = tor_malloc_zero(sizeof(routerinfo_t));
mock_routerinfo->nickname = tor_strdup("ConlonNancarrow");
mock_routerinfo->addr = 123456789;
mock_routerinfo->or_port = 443;
mock_routerinfo->platform = tor_strdup("unittest");
mock_routerinfo->cache_info.published_on = now;
mock_routerinfo->identity_pkey = crypto_pk_dup_key(ident_key);
mock_routerinfo->onion_pkey = crypto_pk_dup_key(tap_key);
mock_routerinfo->bandwidthrate = 9001;
mock_routerinfo->bandwidthburst = 9002;
}
return mock_routerinfo;
}
/* If no distribution option was set, then check_bridge_distribution_setting()
* should have set it to "any". */
static void
test_router_dump_router_to_string_no_bridge_distribution_method(void *arg) {
const char* needle = "bridge-distribution-request any";
or_options_t* options = get_options_mutable();
routerinfo_t* router = NULL;
curve25519_keypair_t ntor_keypair;
ed25519_keypair_t signing_keypair;
char* desc = NULL;
char* found = NULL;
(void)arg;
NS_MOCK(router_get_my_routerinfo);
options->ORPort_set = 1;
options->BridgeRelay = 1;
/* Generate keys which router_dump_router_to_string() expects to exist. */
tt_int_op(0, ==, curve25519_keypair_generate(&ntor_keypair, 0));
tt_int_op(0, ==, ed25519_keypair_generate(&signing_keypair, 0));
/* Set up part of our routerinfo_t so that we don't trigger any other
* assertions in router_dump_router_to_string(). */
router = (routerinfo_t*)router_get_my_routerinfo();
tt_ptr_op(router, !=, NULL);
router->onion_curve25519_pkey = &ntor_keypair.pubkey;
/* Generate our server descriptor and ensure that the substring
* "bridge-distribution-request any" occurs somewhere within it. */
desc = router_dump_router_to_string(router,
router->identity_pkey,
router->onion_pkey,
&ntor_keypair,
&signing_keypair);
tt_ptr_op(desc, !=, NULL);
found = strstr(desc, needle);
tt_ptr_op(found, !=, NULL);
done:
NS_UNMOCK(router_get_my_routerinfo);
tor_free(desc);
}
#define ROUTER_TEST(name, flags) \
{ #name, test_router_ ## name, flags, NULL, NULL }
struct testcase_t router_tests[] = {
ROUTER_TEST(dump_router_to_string_no_bridge_distribution_method, TT_FORK),
END_OF_TESTCASES
};