Sfoglia il codice sorgente

Merge branch 'feature18329_029_squashed' into maint-0.3.2

Nick Mathewson 6 anni fa
parent
commit
594cf92498
10 ha cambiato i file con 273 aggiunte e 1 eliminazioni
  1. 9 0
      changes/feature18329
  2. 11 0
      doc/tor.1.txt
  3. 61 1
      src/or/config.c
  4. 2 0
      src/or/config.h
  5. 4 0
      src/or/or.h
  6. 12 0
      src/or/router.c
  7. 1 0
      src/test/include.am
  8. 1 0
      src/test/test.c
  9. 63 0
      src/test/test_config.c
  10. 109 0
      src/test/test_router.c

+ 9 - 0
changes/feature18329

@@ -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.
+

+ 11 - 0
doc/tor.1.txt

@@ -1670,6 +1670,17 @@ is non-zero):
     server descriptor to the bridge database, rather than
     server descriptor to the bridge database, rather than
     to the public directory authorities.
     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__::
 [[ContactInfo]] **ContactInfo** __email_address__::
     Administrative contact information for this relay or bridge. This line
     Administrative contact information for this relay or bridge. This line
     can be used to contact you if your relay or bridge is misconfigured or
     can be used to contact you if your relay or bridge is misconfigured or

+ 61 - 1
src/or/config.c

@@ -253,6 +253,7 @@ static config_var_t option_vars_[] = {
   V(BridgePassword,              STRING,   NULL),
   V(BridgePassword,              STRING,   NULL),
   V(BridgeRecordUsageByCountry,  BOOL,     "1"),
   V(BridgeRecordUsageByCountry,  BOOL,     "1"),
   V(BridgeRelay,                 BOOL,     "0"),
   V(BridgeRelay,                 BOOL,     "0"),
+  V(BridgeDistribution,          STRING,   NULL),
   V(CellStatistics,              BOOL,     "0"),
   V(CellStatistics,              BOOL,     "0"),
   V(PaddingStatistics,           BOOL,     "1"),
   V(PaddingStatistics,           BOOL,     "1"),
   V(LearnCircuitBuildTimeout,    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,
 static int check_server_ports(const smartlist_t *ports,
                               const or_options_t *options,
                               const or_options_t *options,
                               int *num_low_ports_out);
                               int *num_low_ports_out);
-
 static int validate_data_directory(or_options_t *options);
 static int validate_data_directory(or_options_t *options);
 static int write_configuration_file(const char *fname,
 static int write_configuration_file(const char *fname,
                                     const or_options_t *options);
                                     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. ");
     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) {
   if (options->MinUptimeHidServDirectoryV2 < 0) {
     log_warn(LD_CONFIG, "MinUptimeHidServDirectoryV2 option must be at "
     log_warn(LD_CONFIG, "MinUptimeHidServDirectoryV2 option must be at "
                         "least 0 seconds. Changing to 0.");
                         "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(old_options) !=
         get_effective_bwburst(new_options) ||
         get_effective_bwburst(new_options) ||
       !opt_streq(old_options->ContactInfo, new_options->ContactInfo) ||
       !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) ||
       !config_lines_eq(old_options->MyFamily, new_options->MyFamily) ||
       !opt_streq(old_options->AccountingStart, new_options->AccountingStart) ||
       !opt_streq(old_options->AccountingStart, new_options->AccountingStart) ||
       old_options->AccountingMax != new_options->AccountingMax ||
       old_options->AccountingMax != new_options->AccountingMax ||
@@ -6583,6 +6594,55 @@ warn_client_dns_cache(const char *option, int disabling)
       "to your destination.");
       "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.
  * Parse port configuration for a single port type.
  *
  *

+ 2 - 0
src/or/config.h

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

+ 4 - 0
src/or/or.h

@@ -3770,6 +3770,10 @@ typedef struct {
   int BridgeAuthoritativeDir; /**< Boolean: is this an authoritative directory
   int BridgeAuthoritativeDir; /**< Boolean: is this an authoritative directory
                                * that aggregates bridge descriptors? */
                                * 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
   /** If set on a bridge authority, it will answer requests on its dirport
    * for bridge statuses -- but only if the requests use this password. */
    * for bridge statuses -- but only if the requests use this password. */
   char *BridgePassword;
   char *BridgePassword;

+ 12 - 0
src/or/router.c

@@ -2956,6 +2956,18 @@ router_dump_router_to_string(routerinfo_t *router,
     smartlist_add_asprintf(chunks, "contact %s\n", ci);
     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) {
   if (router->onion_curve25519_pkey) {
     char kbuf[128];
     char kbuf[128];
     base64_encode(kbuf, sizeof(kbuf),
     base64_encode(kbuf, sizeof(kbuf),

+ 1 - 0
src/test/include.am

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

+ 1 - 0
src/test/test.c

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

+ 63 - 0
src/test/test_config.c

@@ -5446,6 +5446,65 @@ test_config_dup_and_filter(void *arg)
   config_free_lines(line_dup);
   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)                          \
 #define CONFIG_TEST(name, flags)                          \
   { #name, test_config_ ## name, flags, NULL, NULL }
   { #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_torrc_only, TT_FORK),
   CONFIG_TEST(include_flag_defaults_only, TT_FORK),
   CONFIG_TEST(include_flag_defaults_only, TT_FORK),
   CONFIG_TEST(dup_and_filter, 0),
   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
   END_OF_TESTCASES
 };
 };
 
 

+ 109 - 0
src/test/test_router.c

@@ -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
+};