[tor-commits] [tor/master] Merge branch 'ticket33029_042_01' into ticket33029_043_03

nickm at torproject.org nickm at torproject.org
Thu Feb 20 13:51:04 UTC 2020


commit f0964628e6e6b4f5dda6df30fbb19f74c59eccfd
Merge: de31c4757 7b4d9fabe
Author: David Goulet <dgoulet at torproject.org>
Date:   Tue Feb 11 10:30:29 2020 -0500

    Merge branch 'ticket33029_042_01' into ticket33029_043_03
    
    Conflicts:
            doc/tor.1.txt
            src/app/config/config.c
            src/app/config/or_options_st.h
            src/core/mainloop/connection.h
    
    Between 042 and 043, the dirauth options were modularized so this merge commit
    address this by moving the AuthDirRejectUncompressedRequests to the module
    along with a series of accessors.
    
    Signed-off-by: David Goulet <dgoulet at torproject.org>

 changes/ticket33029                      |   5 +
 doc/tor.1.txt                            |  10 +-
 scripts/maint/practracker/exceptions.txt |   2 +-
 src/core/mainloop/connection.c           |  56 ++++----
 src/core/mainloop/connection.h           |   4 +-
 src/feature/dirauth/dirauth_config.c     |   9 ++
 src/feature/dirauth/dirauth_config.h     |   4 +
 src/feature/dirauth/dirauth_options.inc  |   7 +
 src/feature/dircache/dircache.c          |  13 +-
 src/feature/nodelist/dirlist.c           |  31 +++++
 src/feature/nodelist/dirlist.h           |   2 +
 src/feature/nodelist/nodelist.c          |  43 ++++--
 src/feature/nodelist/nodelist.h          |   2 +
 src/test/test_address_set.c              |  15 ++-
 src/test/test_bwmgt.c                    | 217 ++++++++++++++++++++++++++++++-
 15 files changed, 371 insertions(+), 49 deletions(-)

diff --cc scripts/maint/practracker/exceptions.txt
index 70e6a5519,7b15b37f8..d89b80c1b
--- a/scripts/maint/practracker/exceptions.txt
+++ b/scripts/maint/practracker/exceptions.txt
@@@ -73,12 -68,12 +73,12 @@@ problem function-size /src/core/mainloo
  problem function-size /src/core/mainloop/connection.c:connection_buf_read_from_socket() 180
  problem function-size /src/core/mainloop/connection.c:connection_handle_write_impl() 241
  problem function-size /src/core/mainloop/connection.c:assert_connection_ok() 143
--problem dependency-violation /src/core/mainloop/connection.c 44
++problem dependency-violation /src/core/mainloop/connection.c 47
  problem dependency-violation /src/core/mainloop/cpuworker.c 12
 -problem include-count /src/core/mainloop/mainloop.c 63
 +problem include-count /src/core/mainloop/mainloop.c 64
  problem function-size /src/core/mainloop/mainloop.c:conn_close_if_marked() 108
  problem function-size /src/core/mainloop/mainloop.c:run_connection_housekeeping() 123
 -problem dependency-violation /src/core/mainloop/mainloop.c 49
 +problem dependency-violation /src/core/mainloop/mainloop.c 50
  problem dependency-violation /src/core/mainloop/mainloop_pubsub.c 1
  problem dependency-violation /src/core/mainloop/mainloop_sys.c 1
  problem dependency-violation /src/core/mainloop/netstatus.c 4
diff --cc src/core/mainloop/connection.c
index 4a2dc21f1,50cd3810a..bfd850da8
--- a/src/core/mainloop/connection.c
+++ b/src/core/mainloop/connection.c
@@@ -91,6 -91,6 +91,7 @@@
  #include "feature/control/control.h"
  #include "feature/control/control_events.h"
  #include "feature/dirauth/authmode.h"
++#include "feature/dirauth/dirauth_config.h"
  #include "feature/dircache/dirserv.h"
  #include "feature/dircommon/directory.h"
  #include "feature/hibernate/hibernate.h"
@@@ -3297,14 -3211,27 +3298,27 @@@ connection_dir_is_global_write_low(cons
    size_t smaller_bucket =
      MIN(token_bucket_rw_get_write(&global_bucket),
          token_bucket_rw_get_write(&global_relayed_bucket));
-   if (authdir_mode(get_options()) && priority>1)
-     return 0; /* there's always room to answer v2 if we're an auth dir */
+ 
+   /* Special case for authorities (directory only). */
+   if (authdir_mode_v3(get_options())) {
+     /* Are we configured to possibly reject requests under load? */
 -    if (!get_options()->AuthDirRejectRequestsUnderLoad) {
++    if (!dirauth_should_reject_requests_under_load()) {
+       /* Answer request no matter what. */
+       return false;
+     }
+     /* Always answer requests from a known relay which includes the other
+      * authorities. The following looks up the addresses for relays that we
+      * have their descriptor _and_ any configured trusted directories. */
+     if (nodelist_probably_contains_address(&conn->addr)) {
+       return false;
+     }
+   }
  
    if (!connection_is_rate_limited(conn))
-     return 0; /* local conns don't get limited */
+     return false; /* local conns don't get limited */
  
    if (smaller_bucket < attempt)
-     return 1; /* not enough space no matter the priority */
+     return true; /* not enough space. */
  
    {
      const time_t diff = approx_time() - write_buckets_last_empty_at;
diff --cc src/core/mainloop/connection.h
index 0ab601d86,668c74004..bcd3d590a
--- a/src/core/mainloop/connection.h
+++ b/src/core/mainloop/connection.h
@@@ -219,26 -196,23 +219,26 @@@ void connection_mark_all_noncontrol_lis
  void connection_mark_all_noncontrol_connections(void);
  
  ssize_t connection_bucket_write_limit(struct connection_t *conn, time_t now);
- int global_write_bucket_low(struct connection_t *conn,
-                             size_t attempt, int priority);
+ bool connection_dir_is_global_write_low(const struct connection_t *conn,
+                                         size_t attempt);
  void connection_bucket_init(void);
 -void connection_bucket_adjust(const or_options_t *options);
 +void connection_bucket_adjust(const struct or_options_t *options);
  void connection_bucket_refill_all(time_t now,
                                    uint32_t now_ts);
 -void connection_read_bw_exhausted(connection_t *conn, bool is_global_bw);
 -void connection_write_bw_exhausted(connection_t *conn, bool is_global_bw);
 -void connection_consider_empty_read_buckets(connection_t *conn);
 -void connection_consider_empty_write_buckets(connection_t *conn);
 -
 -int connection_handle_read(connection_t *conn);
 -
 -int connection_buf_get_bytes(char *string, size_t len, connection_t *conn);
 -int connection_buf_get_line(connection_t *conn, char *data,
 -                                   size_t *data_len);
 -int connection_fetch_from_buf_http(connection_t *conn,
 +void connection_read_bw_exhausted(struct connection_t *conn,
 +                                  bool is_global_bw);
 +void connection_write_bw_exhausted(struct connection_t *conn,
 +                                   bool is_global_bw);
 +void connection_consider_empty_read_buckets(struct connection_t *conn);
 +void connection_consider_empty_write_buckets(struct connection_t *conn);
 +
 +int connection_handle_read(struct connection_t *conn);
 +
 +int connection_buf_get_bytes(char *string, size_t len,
 +                             struct connection_t *conn);
 +int connection_buf_get_line(struct connection_t *conn, char *data,
 +                            size_t *data_len);
 +int connection_fetch_from_buf_http(struct connection_t *conn,
                                 char **headers_out, size_t max_headerlen,
                                 char **body_out, size_t *body_used,
                                 size_t max_bodylen, int force_complete);
diff --cc src/feature/dirauth/dirauth_config.c
index 3aeeab3b3,000000000..ca16dc842
mode 100644,000000..100644
--- a/src/feature/dirauth/dirauth_config.c
+++ b/src/feature/dirauth/dirauth_config.c
@@@ -1,461 -1,0 +1,470 @@@
 +/* Copyright (c) 2001 Matej Pfajfar.
 + * Copyright (c) 2001-2004, Roger Dingledine.
 + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
 + * Copyright (c) 2007-2020, The Tor Project, Inc. */
 +/* See LICENSE for licensing information */
 +
 +/**
 + * @file dirauth_config.c
 + * @brief Code to interpret the user's configuration of Tor's directory
 + *        authority module.
 + **/
 +
 +#include "orconfig.h"
 +#include "feature/dirauth/dirauth_config.h"
 +
 +#include "lib/encoding/confline.h"
 +#include "lib/confmgt/confmgt.h"
 +#include "lib/conf/confdecl.h"
 +
 +/* Required for dirinfo_type_t in or_options_t */
 +#include "core/or/or.h"
 +#include "app/config/config.h"
 +
 +#include "feature/dircommon/voting_schedule.h"
 +#include "feature/stats/rephist.h"
 +
 +#include "feature/dirauth/authmode.h"
 +#include "feature/dirauth/bwauth.h"
 +#include "feature/dirauth/dirauth_periodic.h"
++#include "feature/dirauth/dirauth_sys.h"
 +#include "feature/dirauth/dirvote.h"
 +#include "feature/dirauth/guardfraction.h"
 +#include "feature/dirauth/dirauth_options_st.h"
 +
 +/* Copied from config.c, we will refactor later in 29211. */
 +#define REJECT(arg) \
 +  STMT_BEGIN *msg = tor_strdup(arg); return -1; STMT_END
 +#if defined(__GNUC__) && __GNUC__ <= 3
 +#define COMPLAIN(args...) \
 +  STMT_BEGIN log_warn(LD_CONFIG, args); STMT_END
 +#else
 +#define COMPLAIN(args, ...)                                     \
 +  STMT_BEGIN log_warn(LD_CONFIG, args, ##__VA_ARGS__); STMT_END
 +#endif /* defined(__GNUC__) && __GNUC__ <= 3 */
 +
 +#define YES_IF_CHANGED_INT(opt) \
 +  if (!CFG_EQ_INT(old_options, new_options, opt)) return 1;
 +
++/** Return true iff we are configured to reject request under load for non
++ * relay connections. */
++bool
++dirauth_should_reject_requests_under_load(void)
++{
++  return !!dirauth_get_options()->AuthDirRejectRequestsUnderLoad;
++}
++
 +/**
 + * Legacy validation/normalization function for the dirauth mode options in
 + * options. Uses old_options as the previous options.
 + *
 + * Returns 0 on success, returns -1 and sets *msg to a newly allocated string
 + * on error.
 + */
 +int
 +options_validate_dirauth_mode(const or_options_t *old_options,
 +                              or_options_t *options,
 +                              char **msg)
 +{
 +  if (BUG(!options))
 +    return -1;
 +
 +  if (BUG(!msg))
 +    return -1;
 +
 +  if (!authdir_mode(options))
 +    return 0;
 +
 +  /* confirm that our address isn't broken, so we can complain now */
 +  uint32_t tmp;
 +  if (resolve_my_address(LOG_WARN, options, &tmp, NULL, NULL) < 0)
 +    REJECT("Failed to resolve/guess local address. See logs for details.");
 +
 +  if (!options->ContactInfo && !options->TestingTorNetwork)
 +    REJECT("Authoritative directory servers must set ContactInfo");
 +
 +  if (options->UseEntryGuards) {
 +    log_info(LD_CONFIG, "Authoritative directory servers can't set "
 +             "UseEntryGuards. Disabling.");
 +    options->UseEntryGuards = 0;
 +  }
 +  if (!options->DownloadExtraInfo && authdir_mode_v3(options)) {
 +    log_info(LD_CONFIG, "Authoritative directories always try to download "
 +             "extra-info documents. Setting DownloadExtraInfo.");
 +    options->DownloadExtraInfo = 1;
 +  }
 +  if (!(options->BridgeAuthoritativeDir ||
 +        options->V3AuthoritativeDir))
 +    REJECT("AuthoritativeDir is set, but none of "
 +           "(Bridge/V3)AuthoritativeDir is set.");
 +
 +  /* If we have a v3bandwidthsfile and it's broken, complain on startup */
 +  if (options->V3BandwidthsFile && !old_options) {
 +    dirserv_read_measured_bandwidths(options->V3BandwidthsFile, NULL, NULL,
 +                                     NULL);
 +  }
 +  /* same for guardfraction file */
 +  if (options->GuardfractionFile && !old_options) {
 +    dirserv_read_guardfraction_file(options->GuardfractionFile, NULL);
 +  }
 +
 +  if (!options->DirPort_set)
 +    REJECT("Running as authoritative directory, but no DirPort set.");
 +
 +  if (!options->ORPort_set)
 +    REJECT("Running as authoritative directory, but no ORPort set.");
 +
 +  if (options->ClientOnly)
 +    REJECT("Running as authoritative directory, but ClientOnly also set.");
 +
 +  return 0;
 +}
 +
 +/**
 + * Legacy validation/normalization function for the dirauth schedule options
 + * in options. Uses old_options as the previous options.
 + *
 + * Returns 0 on success, returns -1 and sets *msg to a newly allocated string
 + * on error.
 + */
 +int
 +options_validate_dirauth_schedule(const or_options_t *old_options,
 +                                  or_options_t *options,
 +                                  char **msg)
 +{
 +  (void)old_options;
 +
 +  if (BUG(!options))
 +    return -1;
 +
 +  if (BUG(!msg))
 +    return -1;
 +
 +  if (!authdir_mode_v3(options))
 +    return 0;
 +
 +  if (options->V3AuthVoteDelay + options->V3AuthDistDelay >=
 +      options->V3AuthVotingInterval/2) {
 +    REJECT("V3AuthVoteDelay plus V3AuthDistDelay must be less than half "
 +           "V3AuthVotingInterval");
 +  }
 +
 +  if (options->V3AuthVoteDelay < MIN_VOTE_SECONDS) {
 +    if (options->TestingTorNetwork) {
 +      if (options->V3AuthVoteDelay < MIN_VOTE_SECONDS_TESTING) {
 +        REJECT("V3AuthVoteDelay is way too low.");
 +      } else {
 +        COMPLAIN("V3AuthVoteDelay is very low. "
 +                 "This may lead to failure to vote for a consensus.");
 +      }
 +    } else {
 +      REJECT("V3AuthVoteDelay is way too low.");
 +    }
 +  }
 +
 +  if (options->V3AuthDistDelay < MIN_DIST_SECONDS) {
 +    if (options->TestingTorNetwork) {
 +      if (options->V3AuthDistDelay < MIN_DIST_SECONDS_TESTING) {
 +        REJECT("V3AuthDistDelay is way too low.");
 +      } else {
 +        COMPLAIN("V3AuthDistDelay is very low. "
 +                 "This may lead to missing votes in a consensus.");
 +      }
 +    } else {
 +      REJECT("V3AuthDistDelay is way too low.");
 +    }
 +  }
 +
 +  if (options->V3AuthNIntervalsValid < 2)
 +    REJECT("V3AuthNIntervalsValid must be at least 2.");
 +
 +  if (options->V3AuthVotingInterval < MIN_VOTE_INTERVAL) {
 +    if (options->TestingTorNetwork) {
 +      if (options->V3AuthVotingInterval < MIN_VOTE_INTERVAL_TESTING) {
 +        /* Unreachable, covered by earlier checks */
 +        REJECT("V3AuthVotingInterval is insanely low."); /* LCOV_EXCL_LINE */
 +      } else {
 +        COMPLAIN("V3AuthVotingInterval is very low. "
 +                 "This may lead to failure to synchronise for a consensus.");
 +      }
 +    } else {
 +      REJECT("V3AuthVotingInterval is insanely low.");
 +    }
 +  } else if (options->V3AuthVotingInterval > 24*60*60) {
 +    REJECT("V3AuthVotingInterval is insanely high.");
 +  } else if (((24*60*60) % options->V3AuthVotingInterval) != 0) {
 +    COMPLAIN("V3AuthVotingInterval does not divide evenly into 24 hours.");
 +  }
 +
 +  return 0;
 +}
 +
 +/**
 + * Legacy validation/normalization function for the dirauth testing options
 + * in options. Uses old_options as the previous options.
 + *
 + * Returns 0 on success, returns -1 and sets *msg to a newly allocated string
 + * on error.
 + */
 +int
 +options_validate_dirauth_testing(const or_options_t *old_options,
 +                                 or_options_t *options,
 +                                 char **msg)
 +{
 +  (void)old_options;
 +
 +  if (BUG(!options))
 +    return -1;
 +
 +  if (BUG(!msg))
 +    return -1;
 +
 +  if (!authdir_mode(options))
 +    return 0;
 +
 +  if (!authdir_mode_v3(options))
 +    return 0;
 +
 +  if (options->TestingV3AuthInitialVotingInterval
 +      < MIN_VOTE_INTERVAL_TESTING_INITIAL) {
 +    REJECT("TestingV3AuthInitialVotingInterval is insanely low.");
 +  } else if (((30*60) % options->TestingV3AuthInitialVotingInterval) != 0) {
 +    REJECT("TestingV3AuthInitialVotingInterval does not divide evenly into "
 +           "30 minutes.");
 +  }
 +
 +  if (options->TestingV3AuthInitialVoteDelay < MIN_VOTE_SECONDS_TESTING) {
 +    REJECT("TestingV3AuthInitialVoteDelay is way too low.");
 +  }
 +
 +  if (options->TestingV3AuthInitialDistDelay < MIN_DIST_SECONDS_TESTING) {
 +    REJECT("TestingV3AuthInitialDistDelay is way too low.");
 +  }
 +
 +  if (options->TestingV3AuthInitialVoteDelay +
 +      options->TestingV3AuthInitialDistDelay >=
 +      options->TestingV3AuthInitialVotingInterval) {
 +    REJECT("TestingV3AuthInitialVoteDelay plus TestingV3AuthInitialDistDelay "
 +           "must be less than TestingV3AuthInitialVotingInterval");
 +  }
 +
 +  if (options->TestingV3AuthVotingStartOffset >
 +      MIN(options->TestingV3AuthInitialVotingInterval,
 +          options->V3AuthVotingInterval)) {
 +    REJECT("TestingV3AuthVotingStartOffset is higher than the voting "
 +           "interval.");
 +  } else if (options->TestingV3AuthVotingStartOffset < 0) {
 +    REJECT("TestingV3AuthVotingStartOffset must be non-negative.");
 +  }
 +
 +  return 0;
 +}
 +
 +/**
 + * Return true if changing the configuration from <b>old</b> to <b>new</b>
 + * affects the timing of the voting subsystem
 + */
 +static int
 +options_transition_affects_dirauth_timing(const or_options_t *old_options,
 +                                          const or_options_t *new_options)
 +{
 +  tor_assert(old_options);
 +  tor_assert(new_options);
 +
 +  if (authdir_mode_v3(old_options) != authdir_mode_v3(new_options))
 +    return 1;
 +  if (! authdir_mode_v3(new_options))
 +    return 0;
 +
 +  YES_IF_CHANGED_INT(V3AuthVotingInterval);
 +  YES_IF_CHANGED_INT(V3AuthVoteDelay);
 +  YES_IF_CHANGED_INT(V3AuthDistDelay);
 +  YES_IF_CHANGED_INT(TestingV3AuthInitialVotingInterval);
 +  YES_IF_CHANGED_INT(TestingV3AuthInitialVoteDelay);
 +  YES_IF_CHANGED_INT(TestingV3AuthInitialDistDelay);
 +  YES_IF_CHANGED_INT(TestingV3AuthVotingStartOffset);
 +
 +  return 0;
 +}
 +
 +/** Fetch the active option list, and take dirauth actions based on it. All of
 + * the things we do should survive being done repeatedly.  If present,
 + * <b>old_options</b> contains the previous value of the options.
 + *
 + * Return 0 if all goes well, return -1 if it's time to die.
 + *
 + * Note: We haven't moved all the "act on new configuration" logic
 + * into the options_act* functions yet.  Some is still in do_hup() and other
 + * places.
 + */
 +int
 +options_act_dirauth(const or_options_t *old_options)
 +{
 +  const or_options_t *options = get_options();
 +
 +  /* We may need to reschedule some dirauth stuff if our status changed. */
 +  if (old_options) {
 +    if (options_transition_affects_dirauth_timing(old_options, options)) {
 +      voting_schedule_recalculate_timing(options, time(NULL));
 +      reschedule_dirvote(options);
 +    }
 +  }
 +
 +  return 0;
 +}
 +
 +/** Fetch the active option list, and take dirauth mtbf actions based on it.
 + * All of the things we do should survive being done repeatedly.  If present,
 + * <b>old_options</b> contains the previous value of the options.
 + *
 + * Must be called immediately after a successful or_state_load().
 + *
 + * Return 0 if all goes well, return -1 if it's time to die.
 + *
 + * Note: We haven't moved all the "act on new configuration" logic
 + * into the options_act* functions yet.  Some is still in do_hup() and other
 + * places.
 + */
 +int
 +options_act_dirauth_mtbf(const or_options_t *old_options)
 +{
 +  (void)old_options;
 +
 +  const or_options_t *options = get_options();
 +  int running_tor = options->command == CMD_RUN_TOR;
 +
 +  if (!authdir_mode(options))
 +    return 0;
 +
 +  /* Load dirauth state */
 +  if (running_tor) {
 +    rep_hist_load_mtbf_data(time(NULL));
 +  }
 +
 +  return 0;
 +}
 +
 +/** Fetch the active option list, and take dirauth statistics actions based
 + * on it. All of the things we do should survive being done repeatedly. If
 + * present, <b>old_options</b> contains the previous value of the options.
 + *
 + * Sets <b>*print_notice_out</b> if we enabled stats, and need to print
 + * a stats log using options_act_relay_stats_msg().
 + *
 + * Return 0 if all goes well, return -1 if it's time to die.
 + *
 + * Note: We haven't moved all the "act on new configuration" logic
 + * into the options_act* functions yet.  Some is still in do_hup() and other
 + * places.
 + */
 +int
 +options_act_dirauth_stats(const or_options_t *old_options,
 +                          bool *print_notice_out)
 +{
 +  if (BUG(!print_notice_out))
 +    return -1;
 +
 +  const or_options_t *options = get_options();
 +
 +  if (authdir_mode_bridge(options)) {
 +    time_t now = time(NULL);
 +    int print_notice = 0;
 +
 +    if (!old_options || !authdir_mode_bridge(old_options)) {
 +      rep_hist_desc_stats_init(now);
 +      print_notice = 1;
 +    }
 +    if (print_notice)
 +      *print_notice_out = 1;
 +  }
 +
 +  /* If we used to have statistics enabled but we just disabled them,
 +     stop gathering them.  */
 +  if (old_options && authdir_mode_bridge(old_options) &&
 +      !authdir_mode_bridge(options))
 +    rep_hist_desc_stats_term();
 +
 +  return 0;
 +}
 +
 +/**
 + * Make any necessary modifications to a dirauth_options_t that occur
 + * before validation.  On success return 0; on failure return -1 and
 + * set *<b>msg_out</b> to a newly allocated error string.
 + **/
 +static int
 +dirauth_options_pre_normalize(void *arg, char **msg_out)
 +{
 +  dirauth_options_t *options = arg;
 +  (void)msg_out;
 +
 +  if (!options->RecommendedClientVersions)
 +    options->RecommendedClientVersions =
 +      config_lines_dup(options->RecommendedVersions);
 +  if (!options->RecommendedServerVersions)
 +    options->RecommendedServerVersions =
 +      config_lines_dup(options->RecommendedVersions);
 +
 +  if (config_ensure_bandwidth_cap(&options->AuthDirFastGuarantee,
 +                           "AuthDirFastGuarantee", msg_out) < 0)
 +    return -1;
 +  if (config_ensure_bandwidth_cap(&options->AuthDirGuardBWGuarantee,
 +                                  "AuthDirGuardBWGuarantee", msg_out) < 0)
 +    return -1;
 +
 +  return 0;
 +}
 +
 +/**
 + * Check whether a dirauth_options_t is correct.
 + *
 + * On success return 0; on failure return -1 and set *<b>msg_out</b> to a
 + * newly allocated error string.
 + **/
 +static int
 +dirauth_options_validate(const void *arg, char **msg)
 +{
 +  const dirauth_options_t *options = arg;
 +
 +  if (options->VersioningAuthoritativeDirectory &&
 +      (!options->RecommendedClientVersions ||
 +       !options->RecommendedServerVersions)) {
 +      REJECT("Versioning authoritative dir servers must set "
 +           "Recommended*Versions.");
 +  }
 +
 +  char *t;
 +  /* Call these functions to produce warnings only. */
 +  t = format_recommended_version_list(options->RecommendedClientVersions, 1);
 +  tor_free(t);
 +  t = format_recommended_version_list(options->RecommendedServerVersions, 1);
 +  tor_free(t);
 +
 +  if (options->TestingAuthDirTimeToLearnReachability > 2*60*60) {
 +    COMPLAIN("TestingAuthDirTimeToLearnReachability is insanely high.");
 +  }
 +
 +  return 0;
 +}
 +
 +/* Declare the options field table for dirauth_options */
 +#define CONF_CONTEXT TABLE
 +#include "feature/dirauth/dirauth_options.inc"
 +#undef CONF_CONTEXT
 +
 +/** Magic number for dirauth_options_t. */
 +#define DIRAUTH_OPTIONS_MAGIC 0x41757448
 +
 +/**
 + * Declare the configuration options for the dirauth module.
 + **/
 +const config_format_t dirauth_options_fmt = {
 +  .size = sizeof(dirauth_options_t),
 +  .magic = { "dirauth_options_t",
 +             DIRAUTH_OPTIONS_MAGIC,
 +             offsetof(dirauth_options_t, magic) },
 +  .vars = dirauth_options_t_vars,
 +
 +  .pre_normalize_fn = dirauth_options_pre_normalize,
 +  .validate_fn = dirauth_options_validate
 +};
diff --cc src/feature/dirauth/dirauth_config.h
index 2ebafd917,000000000..1ec599717
mode 100644,000000..100644
--- a/src/feature/dirauth/dirauth_config.h
+++ b/src/feature/dirauth/dirauth_config.h
@@@ -1,83 -1,0 +1,87 @@@
 +/* Copyright (c) 2001 Matej Pfajfar.
 + * Copyright (c) 2001-2004, Roger Dingledine.
 + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
 + * Copyright (c) 2007-2020, The Tor Project, Inc. */
 +/* See LICENSE for licensing information */
 +
 +/**
 + * @file dirauth_config.h
 + * @brief Header for feature/dirauth/dirauth_config.c
 + **/
 +
 +#ifndef TOR_FEATURE_DIRAUTH_DIRAUTH_CONFIG_H
 +#define TOR_FEATURE_DIRAUTH_DIRAUTH_CONFIG_H
 +
 +struct or_options_t;
 +
 +#ifdef HAVE_MODULE_DIRAUTH
 +
 +#include "lib/cc/torint.h"
 +
 +int options_validate_dirauth_mode(const struct or_options_t *old_options,
 +                                  struct or_options_t *options,
 +                                  char **msg);
 +
 +int options_validate_dirauth_schedule(const struct or_options_t *old_options,
 +                                      struct or_options_t *options,
 +                                      char **msg);
 +
 +int options_validate_dirauth_testing(const struct or_options_t *old_options,
 +                                     struct or_options_t *options,
 +                                     char **msg);
 +
 +int options_act_dirauth(const struct or_options_t *old_options);
 +int options_act_dirauth_mtbf(const struct or_options_t *old_options);
 +int options_act_dirauth_stats(const struct or_options_t *old_options,
 +                              bool *print_notice_out);
 +
++bool dirauth_should_reject_requests_under_load(void);
++
 +extern const struct config_format_t dirauth_options_fmt;
 +
 +#else /* !defined(HAVE_MODULE_DIRAUTH) */
 +
 +/** When tor is compiled with the dirauth module disabled, it can't be
 + * configured as a directory authority.
 + *
 + * Returns -1 and sets msg to a newly allocated string, if AuthoritativeDir
 + * is set in options. Otherwise returns 0. */
 +static inline int
 +options_validate_dirauth_mode(const struct or_options_t *old_options,
 +                              struct or_options_t *options,
 +                              char **msg)
 +{
 +  (void)old_options;
 +
 +  /* Only check the primary option for now, #29211 will disable more
 +   * options. */
 +  if (options->AuthoritativeDir) {
 +    /* REJECT() this configuration */
 +    *msg = tor_strdup("This tor was built with dirauth mode disabled. "
 +                      "It can not be configured with AuthoritativeDir 1.");
 +    return -1;
 +  }
 +
 +  return 0;
 +}
 +
 +#define options_validate_dirauth_schedule(old_options, options, msg) \
 +  (((void)(old_options)),((void)(options)),((void)(msg)),0)
 +#define options_validate_dirauth_testing(old_options, options, msg) \
 +  (((void)(old_options)),((void)(options)),((void)(msg)),0)
 +#define options_validate_dirauth_testing(old_options, options, msg) \
 +  (((void)(old_options)),((void)(options)),((void)(msg)),0)
 +
 +#define options_act_dirauth(old_options) \
 +  (((void)(old_options)),0)
 +#define options_act_dirauth_mtbf(old_options) \
 +  (((void)(old_options)),0)
 +
 +#define options_act_dirauth_stats(old_options, print_notice_out) \
 +  (((void)(old_options)),((void)(print_notice_out)),0)
 +
++#define dirauth_should_reject_requests_under_load() (false)
++
 +#endif /* defined(HAVE_MODULE_DIRAUTH) */
 +
 +#endif /* !defined(TOR_FEATURE_DIRAUTH_DIRAUTH_CONFIG_H) */
diff --cc src/feature/dirauth/dirauth_options.inc
index 5939010fe,000000000..21f4996c3
mode 100644,000000..100644
--- a/src/feature/dirauth/dirauth_options.inc
+++ b/src/feature/dirauth/dirauth_options.inc
@@@ -1,98 -1,0 +1,105 @@@
 +/* Copyright (c) 2001 Matej Pfajfar.
 + * Copyright (c) 2001-2004, Roger Dingledine.
 + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
 + * Copyright (c) 2007-2019, The Tor Project, Inc. */
 +/* See LICENSE for licensing information */
 +
 +/**
 + * @file dirauth_options.inc
 + * @brief Declare configuration options for the crypto_ops module.
 + **/
 +
 +/** Holds configuration about our directory authority options. */
 +BEGIN_CONF_STRUCT(dirauth_options_t)
 +
 +/** If non-zero, always vote the Fast flag for any relay advertising
 + * this amount of capacity or more. */
 +CONF_VAR(AuthDirFastGuarantee, MEMUNIT, 0, "100 KB")
 +
 +/** If non-zero, this advertised capacity or more is always sufficient
 + * to satisfy the bandwidth requirement for the Guard flag. */
 +CONF_VAR(AuthDirGuardBWGuarantee, MEMUNIT, 0, "2 MB")
 +
 +/** Boolean: are we on IPv6?  */
 +CONF_VAR(AuthDirHasIPv6Connectivity, BOOL, 0, "0")
 +
 +/** True iff we should list bad exits, and vote for all other exits as
 + * good. */
 +CONF_VAR(AuthDirListBadExits, BOOL, 0, "0")
 +
 +/** Do not permit more than this number of servers per IP address. */
 +CONF_VAR(AuthDirMaxServersPerAddr, POSINT, 0, "2")
 +
 +/** Boolean: Do we enforce key-pinning? */
 +CONF_VAR(AuthDirPinKeys, BOOL, 0, "1")
 +
 +/** Bool (default: 1): Switch for the shared random protocol. Only
 + * relevant to a directory authority. If off, the authority won't
 + * participate in the protocol. If on (default), a flag is added to the
 + * vote indicating participation. */
 +CONF_VAR(AuthDirSharedRandomness, BOOL, 0, "1")
 +
 +/** Bool (default: 1): When testing routerinfos as a directory authority,
 + * do we enforce Ed25519 identity match? */
 +/* NOTE: remove this option someday. */
 +CONF_VAR(AuthDirTestEd25519LinkKeys, BOOL, 0, "1")
 +
 +/** Authority only: key=value pairs that we add to our networkstatus
 + * consensus vote on the 'params' line. */
 +CONF_VAR(ConsensusParams, STRING, 0, NULL)
 +
 +/** Authority only: minimum number of measured bandwidths we must see
 + * before we only believe measured bandwidths to assign flags. */
 +CONF_VAR(MinMeasuredBWsForAuthToIgnoreAdvertised, INT, 0, "500")
 +
 +/** As directory authority, accept hidden service directories after what
 + * time? */
 +CONF_VAR(MinUptimeHidServDirectoryV2, INTERVAL, 0, "96 hours")
 +
 +/** Which versions of tor should we tell users to run? */
 +CONF_VAR(RecommendedVersions, LINELIST, 0, NULL)
 +
 +/** Which versions of tor should we tell users to run on clients? */
 +CONF_VAR(RecommendedClientVersions, LINELIST, 0, NULL)
 +
 +/** Which versions of tor should we tell users to run on relays? */
 +CONF_VAR(RecommendedServerVersions, LINELIST, 0, NULL)
 +
 +/** If an authority has been around for less than this amount of time, it
 + * does not believe its reachability information is accurate.  Only
 + * altered on testing networks. */
 +CONF_VAR(TestingAuthDirTimeToLearnReachability, INTERVAL, 0, "30 minutes")
 +
 +  /** Relays in a testing network which should be voted Exit
 +   * regardless of exit policy. */
 +CONF_VAR(TestingDirAuthVoteExit, ROUTERSET, 0, NULL)
 +CONF_VAR(TestingDirAuthVoteExitIsStrict, BOOL, 0, "0")
 +
 +/** Relays in a testing network which should be voted Guard
 + * regardless of uptime and bandwidth. */
 +CONF_VAR(TestingDirAuthVoteGuard, ROUTERSET, 0, NULL)
 +CONF_VAR(TestingDirAuthVoteGuardIsStrict, BOOL, 0, "0")
 +
 +/** Relays in a testing network which should be voted HSDir
 + * regardless of uptime and DirPort. */
 +CONF_VAR(TestingDirAuthVoteHSDir, ROUTERSET, 0, NULL)
 +CONF_VAR(TestingDirAuthVoteHSDirIsStrict, BOOL, 0, "0")
 +
 +/** Minimum value for the Exit flag threshold on testing networks. */
 +CONF_VAR(TestingMinExitFlagThreshold, MEMUNIT, 0, "0")
 +
 +/** Minimum value for the Fast flag threshold on testing networks. */
 +CONF_VAR(TestingMinFastFlagThreshold, MEMUNIT, 0, "0")
 +
 +/** Boolean: is this an authoritative directory that's willing to recommend
 + * versions? */
 +CONF_VAR(VersioningAuthoritativeDirectory, BOOL, 0, "0")
 +
++/** Boolean: Under bandwidth pressure, if set to 1, the authority will always
++ * answer directory requests from relays but will start sending 503 error code
++ * for the other connections. If set to 0, all connections are considered the
++ * same and the authority will try to answer them all regardless of bandwidth
++ * pressure or not. */
++CONF_VAR(AuthDirRejectRequestsUnderLoad, BOOL, 0, "1")
++
 +END_CONF_STRUCT(dirauth_options_t)
diff --cc src/test/test_bwmgt.c
index 1da379698,e6f028ed7..117783caf
--- a/src/test/test_bwmgt.c
+++ b/src/test/test_bwmgt.c
@@@ -6,12 -6,30 +6,33 @@@
   * \brief tests for bandwidth management / token bucket functions
   */
  
+ #define CONFIG_PRIVATE
+ #define CONNECTION_PRIVATE
++#define DIRAUTH_SYS_PRIVATE
  #define TOKEN_BUCKET_PRIVATE
  
  #include "core/or/or.h"
- #include "test/test.h"
  
+ #include "app/config/config.h"
+ #include "core/mainloop/connection.h"
++#include "feature/dirauth/dirauth_sys.h"
+ #include "feature/dircommon/directory.h"
+ #include "feature/nodelist/microdesc.h"
+ #include "feature/nodelist/networkstatus.h"
+ #include "feature/nodelist/nodelist.h"
+ #include "feature/nodelist/routerlist.h"
+ #include "lib/crypt_ops/crypto_rand.h"
  #include "lib/evloop/token_bucket.h"
+ #include "test/test.h"
+ #include "test/test_helpers.h"
+ 
+ #include "app/config/or_options_st.h"
+ #include "core/or/connection_st.h"
++#include "feature/dirauth/dirauth_options_st.h"
+ #include "feature/nodelist/microdesc_st.h"
+ #include "feature/nodelist/networkstatus_st.h"
+ #include "feature/nodelist/routerinfo_st.h"
+ #include "feature/nodelist/routerstatus_st.h"
  
  // an imaginary time, in timestamp units. Chosen so it will roll over.
  static const uint32_t START_TS = UINT32_MAX-10;
@@@ -220,8 -269,162 +272,167 @@@ test_bwmgt_token_buf_helpers(void *arg
    ;
  }
  
+ static void
+ test_bwmgt_dir_conn_global_write_low(void *arg)
+ {
+   bool ret;
+   int addr_family;
+   connection_t *conn = NULL;
+   routerstatus_t *rs = NULL; microdesc_t *md = NULL; routerinfo_t *ri = NULL;
+   tor_addr_t relay_addr;
++  dirauth_options_t *dirauth_opts = NULL;
+ 
+   (void) arg;
+ 
+   memset(&mock_options, 0, sizeof(or_options_t));
+   MOCK(networkstatus_get_latest_consensus,
+        mock_networkstatus_get_latest_consensus);
+   MOCK(networkstatus_get_latest_consensus_by_flavor,
+        mock_networkstatus_get_latest_consensus_by_flavor);
+   MOCK(get_estimated_address_per_node,
+        mock_get_estimated_address_per_node);
+ 
+   /*
+    * The following is rather complex but that is what it takes to add a dummy
+    * consensus with a valid routerlist which will populate our node address
+    * set that we need to lookup to test the known relay code path.
+    *
+    * We MUST do that before we MOCK(get_options) else it is another world of
+    * complexity.
+    */
+ 
+   /* This will be the address of our relay. */
+   tor_addr_parse(&relay_addr, "1.2.3.4");
+ 
+   /* We'll now add a relay into our routerlist and see if we let it. */
+   dummy_ns = tor_malloc_zero(sizeof(*dummy_ns));
+   dummy_ns->flavor = FLAV_MICRODESC;
+   dummy_ns->routerstatus_list = smartlist_new();
+ 
+   md = tor_malloc_zero(sizeof(*md));
+   ri = tor_malloc_zero(sizeof(*ri));
+   rs = tor_malloc_zero(sizeof(*rs));
+   crypto_rand(rs->identity_digest, sizeof(rs->identity_digest));
+   crypto_rand(md->digest, sizeof(md->digest));
+   memcpy(rs->descriptor_digest, md->digest, DIGEST256_LEN);
+ 
+   /* Set IP address. */
+   rs->addr = tor_addr_to_ipv4h(&relay_addr);
+   ri->addr = rs->addr;
+   /* Add the rs to the consensus becoming a node_t. */
+   smartlist_add(dummy_ns->routerstatus_list, rs);
+ 
+   /* Add all configured authorities (hardcoded) before we set the consensus so
+    * the address set exists. */
+   ret = consider_adding_dir_servers(&mock_options, &mock_options);
+   tt_int_op(ret, OP_EQ, 0);
+ 
+   /* This will make the nodelist bloom filter very large
+    * (the_nodelist->node_addrs) so we will fail the contain test rarely. */
+   addr_per_node = 1024;
+ 
+   nodelist_set_consensus(dummy_ns);
+ 
++  dirauth_opts = tor_malloc_zero(sizeof(dirauth_options_t));
++  dirauth_opts->AuthDirRejectRequestsUnderLoad = 0;
++  dirauth_set_options(dirauth_opts);
++
+   /* Ok, now time to control which options we use. */
+   MOCK(get_options, mock_get_options);
+ 
+   /* Set ourselves as an authoritative dir. */
+   mock_options.AuthoritativeDir = 1;
+   mock_options.V3AuthoritativeDir = 1;
+   mock_options.UseDefaultFallbackDirs = 0;
+ 
+   /* This will set our global bucket to 1 byte and thus we will hit the
+    * banwdith limit in our test. */
+   mock_options.BandwidthRate = 1;
+   mock_options.BandwidthBurst = 1;
+ 
+   /* Else an IPv4 address screams. */
+   mock_options.ClientUseIPv4 = 1;
+   mock_options.ClientUseIPv6 = 1;
+ 
+   /* Initialize the global buckets. */
+   connection_bucket_init();
+ 
+   /* The address "127.0.0.1" is set with this helper. */
+   conn = test_conn_get_connection(DIR_CONN_STATE_MIN_, CONN_TYPE_DIR,
+                                   DIR_PURPOSE_MIN_);
+   tt_assert(conn);
+ 
+   /* First try a non authority non relay IP thus a client but we are not
+    * configured to reject requests under load so we should get a false value
+    * that our limit is _not_ low. */
+   addr_family = tor_addr_parse(&conn->addr, "1.1.1.1");
+   tt_int_op(addr_family, OP_EQ, AF_INET);
+   ret = connection_dir_is_global_write_low(conn, INT_MAX);
+   tt_int_op(ret, OP_EQ, 0);
+ 
+   /* Now, we will reject requests under load so try again a non authority non
+    * relay IP thus a client. We should get a warning that our limit is too
+    * low. */
 -  mock_options.AuthDirRejectRequestsUnderLoad = 1;
++  dirauth_opts->AuthDirRejectRequestsUnderLoad = 1;
+ 
+   addr_family = tor_addr_parse(&conn->addr, "1.1.1.1");
+   tt_int_op(addr_family, OP_EQ, AF_INET);
+   ret = connection_dir_is_global_write_low(conn, INT_MAX);
+   tt_int_op(ret, OP_EQ, 1);
+ 
+   /* Now, lets try with a connection address from moria1. It should always
+    * pass even though our limit is too low. */
+   addr_family = tor_addr_parse(&conn->addr, "128.31.0.39");
+   tt_int_op(addr_family, OP_EQ, AF_INET);
+   ret = connection_dir_is_global_write_low(conn, INT_MAX);
+   tt_int_op(ret, OP_EQ, 0);
+ 
+   /* IPv6 testing of gabelmoo. */
+   addr_family = tor_addr_parse(&conn->addr, "[2001:638:a000:4140::ffff:189]");
+   tt_int_op(addr_family, OP_EQ, AF_INET6);
+   ret = connection_dir_is_global_write_low(conn, INT_MAX);
+   tt_int_op(ret, OP_EQ, 0);
+ 
+   /* Lets retry with a known relay address. It should pass. Possible due to
+    * our consensus setting above. */
+   memcpy(&conn->addr, &relay_addr, sizeof(tor_addr_t));
+   ret = connection_dir_is_global_write_low(conn, INT_MAX);
+   tt_int_op(ret, OP_EQ, 0);
+ 
+   /* Lets retry with a random IP that is not an authority nor a relay. */
+   addr_family = tor_addr_parse(&conn->addr, "1.2.3.4");
+   tt_int_op(addr_family, OP_EQ, AF_INET);
+   ret = connection_dir_is_global_write_low(conn, INT_MAX);
+   tt_int_op(ret, OP_EQ, 0);
+ 
+   /* Finally, just make sure it still denies an IP if we are _not_ a v3
+    * directory authority. */
+   mock_options.V3AuthoritativeDir = 0;
+   addr_family = tor_addr_parse(&conn->addr, "1.2.3.4");
+   tt_int_op(addr_family, OP_EQ, AF_INET);
+   ret = connection_dir_is_global_write_low(conn, INT_MAX);
+   tt_int_op(ret, OP_EQ, 1);
+ 
+   /* Random IPv6 should not be allowed. */
+   addr_family = tor_addr_parse(&conn->addr, "[CAFE::ACAB]");
+   tt_int_op(addr_family, OP_EQ, AF_INET6);
+   ret = connection_dir_is_global_write_low(conn, INT_MAX);
+   tt_int_op(ret, OP_EQ, 1);
+ 
+  done:
+   connection_free_minimal(conn);
+   routerstatus_free(rs); routerinfo_free(ri); microdesc_free(md);
+   smartlist_clear(dummy_ns->routerstatus_list);
+   networkstatus_vote_free(dummy_ns);
+ 
+   UNMOCK(get_estimated_address_per_node);
+   UNMOCK(networkstatus_get_latest_consensus);
+   UNMOCK(networkstatus_get_latest_consensus_by_flavor);
+   UNMOCK(get_options);
+ }
+ 
  #define BWMGT(name)                                          \
-   { #name, test_bwmgt_ ## name , 0, NULL, NULL }
+   { #name, test_bwmgt_ ## name , TT_FORK, NULL, NULL }
  
  struct testcase_t bwmgt_tests[] = {
    BWMGT(token_buf_init),





More information about the tor-commits mailing list