tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

dirauth_config.c (16687B)


      1 /* Copyright (c) 2001 Matej Pfajfar.
      2 * Copyright (c) 2001-2004, Roger Dingledine.
      3 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
      4 * Copyright (c) 2007-2021, The Tor Project, Inc. */
      5 /* See LICENSE for licensing information */
      6 
      7 /**
      8 * @file dirauth_config.c
      9 * @brief Code to interpret the user's configuration of Tor's directory
     10 *        authority module.
     11 **/
     12 
     13 #include "orconfig.h"
     14 #include "feature/dirauth/dirauth_config.h"
     15 
     16 #include "lib/encoding/confline.h"
     17 #include "lib/confmgt/confmgt.h"
     18 #include "lib/conf/confdecl.h"
     19 #include "lib/version/torversion.h"
     20 
     21 /* Required for dirinfo_type_t in or_options_t */
     22 #include "core/or/or.h"
     23 #include "core/or/tor_version_st.h"
     24 #include "core/or/versions.h"
     25 #include "app/config/config.h"
     26 #include "app/config/resolve_addr.h"
     27 
     28 #include "feature/dirauth/voting_schedule.h"
     29 #include "feature/stats/rephist.h"
     30 
     31 #include "feature/dirauth/authmode.h"
     32 #include "feature/dirauth/bwauth.h"
     33 #include "feature/dirauth/dirauth_periodic.h"
     34 #include "feature/dirauth/dirauth_sys.h"
     35 #include "feature/dirauth/dirvote.h"
     36 #include "feature/dirauth/guardfraction.h"
     37 #include "feature/dirauth/dirauth_options_st.h"
     38 
     39 /* Copied from config.c, we will refactor later in 29211. */
     40 #define REJECT(arg) \
     41  STMT_BEGIN *msg = tor_strdup(arg); return -1; STMT_END
     42 #if defined(__GNUC__) && __GNUC__ <= 3
     43 #define COMPLAIN(args...) \
     44  STMT_BEGIN log_warn(LD_CONFIG, args); STMT_END
     45 #else
     46 #define COMPLAIN(args, ...)                                     \
     47  STMT_BEGIN log_warn(LD_CONFIG, args, ##__VA_ARGS__); STMT_END
     48 #endif /* defined(__GNUC__) && __GNUC__ <= 3 */
     49 
     50 #define YES_IF_CHANGED_INT(opt) \
     51  if (!CFG_EQ_INT(old_options, new_options, opt)) return 1;
     52 
     53 /** Return true iff we are configured to reject request under load for non
     54 * relay connections. */
     55 bool
     56 dirauth_should_reject_requests_under_load(void)
     57 {
     58  return !!dirauth_get_options()->AuthDirRejectRequestsUnderLoad;
     59 }
     60 
     61 /**
     62 * Legacy validation/normalization function for the dirauth mode options in
     63 * options. Uses old_options as the previous options.
     64 *
     65 * Returns 0 on success, returns -1 and sets *msg to a newly allocated string
     66 * on error.
     67 */
     68 int
     69 options_validate_dirauth_mode(const or_options_t *old_options,
     70                              or_options_t *options,
     71                              char **msg)
     72 {
     73  if (BUG(!options))
     74    return -1;
     75 
     76  if (BUG(!msg))
     77    return -1;
     78 
     79  if (!authdir_mode(options))
     80    return 0;
     81 
     82  /* confirm that our address isn't broken, so we can complain now */
     83  tor_addr_t tmp;
     84  if (!find_my_address(options, AF_INET, LOG_WARN, &tmp, NULL, NULL))
     85    REJECT("Failed to resolve/guess local address. See logs for details.");
     86 
     87  if (!options->ContactInfo && !options->TestingTorNetwork)
     88    REJECT("Authoritative directory servers must set ContactInfo");
     89 
     90  if (options->UseEntryGuards) {
     91    log_info(LD_CONFIG, "Authoritative directory servers can't set "
     92             "UseEntryGuards. Disabling.");
     93    options->UseEntryGuards = 0;
     94  }
     95  if (!options->DownloadExtraInfo && authdir_mode_v3(options)) {
     96    log_info(LD_CONFIG, "Authoritative directories always try to download "
     97             "extra-info documents. Setting DownloadExtraInfo.");
     98    options->DownloadExtraInfo = 1;
     99  }
    100  if (!(options->BridgeAuthoritativeDir ||
    101        options->V3AuthoritativeDir))
    102    REJECT("AuthoritativeDir is set, but none of "
    103           "(Bridge/V3)AuthoritativeDir is set.");
    104 
    105  /* If we have a v3bandwidthsfile and it's broken, complain on startup */
    106  if (options->V3BandwidthsFile && !old_options) {
    107    dirserv_read_measured_bandwidths(options->V3BandwidthsFile, NULL, NULL,
    108                                     NULL);
    109  }
    110  /* same for guardfraction file */
    111  if (options->GuardfractionFile && !old_options) {
    112    dirserv_read_guardfraction_file(options->GuardfractionFile, NULL);
    113  }
    114 
    115  if (!options->DirPort_set)
    116    REJECT("Running as authoritative directory, but no DirPort set.");
    117 
    118  if (!options->ORPort_set)
    119    REJECT("Running as authoritative directory, but no ORPort set.");
    120 
    121  if (options->ClientOnly)
    122    REJECT("Running as authoritative directory, but ClientOnly also set.");
    123 
    124  return 0;
    125 }
    126 
    127 /**
    128 * Legacy validation/normalization function for the dirauth schedule options
    129 * in options. Uses old_options as the previous options.
    130 *
    131 * Returns 0 on success, returns -1 and sets *msg to a newly allocated string
    132 * on error.
    133 */
    134 int
    135 options_validate_dirauth_schedule(const or_options_t *old_options,
    136                                  or_options_t *options,
    137                                  char **msg)
    138 {
    139  (void)old_options;
    140 
    141  if (BUG(!options))
    142    return -1;
    143 
    144  if (BUG(!msg))
    145    return -1;
    146 
    147  if (!authdir_mode_v3(options))
    148    return 0;
    149 
    150  if (options->V3AuthVoteDelay + options->V3AuthDistDelay >=
    151      options->V3AuthVotingInterval/2) {
    152    REJECT("V3AuthVoteDelay plus V3AuthDistDelay must be less than half "
    153           "V3AuthVotingInterval");
    154  }
    155 
    156  if (options->V3AuthVoteDelay < MIN_VOTE_SECONDS) {
    157    if (options->TestingTorNetwork) {
    158      if (options->V3AuthVoteDelay < MIN_VOTE_SECONDS_TESTING) {
    159        REJECT("V3AuthVoteDelay is way too low.");
    160      } else {
    161        COMPLAIN("V3AuthVoteDelay is very low. "
    162                 "This may lead to failure to vote for a consensus.");
    163      }
    164    } else {
    165      REJECT("V3AuthVoteDelay is way too low.");
    166    }
    167  }
    168 
    169  if (options->V3AuthDistDelay < MIN_DIST_SECONDS) {
    170    if (options->TestingTorNetwork) {
    171      if (options->V3AuthDistDelay < MIN_DIST_SECONDS_TESTING) {
    172        REJECT("V3AuthDistDelay is way too low.");
    173      } else {
    174        COMPLAIN("V3AuthDistDelay is very low. "
    175                 "This may lead to missing votes in a consensus.");
    176      }
    177    } else {
    178      REJECT("V3AuthDistDelay is way too low.");
    179    }
    180  }
    181 
    182  if (options->V3AuthNIntervalsValid < 2)
    183    REJECT("V3AuthNIntervalsValid must be at least 2.");
    184 
    185  if (options->V3AuthVotingInterval < MIN_VOTE_INTERVAL) {
    186    if (options->TestingTorNetwork) {
    187      if (options->V3AuthVotingInterval < MIN_VOTE_INTERVAL_TESTING) {
    188        /* Unreachable, covered by earlier checks */
    189        REJECT("V3AuthVotingInterval is insanely low."); /* LCOV_EXCL_LINE */
    190      } else {
    191        COMPLAIN("V3AuthVotingInterval is very low. "
    192                 "This may lead to failure to synchronise for a consensus.");
    193      }
    194    } else {
    195      REJECT("V3AuthVotingInterval is insanely low.");
    196    }
    197  } else if (options->V3AuthVotingInterval > 24*60*60) {
    198    REJECT("V3AuthVotingInterval is insanely high.");
    199  } else if (((24*60*60) % options->V3AuthVotingInterval) != 0) {
    200    COMPLAIN("V3AuthVotingInterval does not divide evenly into 24 hours.");
    201  }
    202 
    203  return 0;
    204 }
    205 
    206 /**
    207 * Legacy validation/normalization function for the dirauth testing options
    208 * in options. Uses old_options as the previous options.
    209 *
    210 * Returns 0 on success, returns -1 and sets *msg to a newly allocated string
    211 * on error.
    212 */
    213 int
    214 options_validate_dirauth_testing(const or_options_t *old_options,
    215                                 or_options_t *options,
    216                                 char **msg)
    217 {
    218  (void)old_options;
    219 
    220  if (BUG(!options))
    221    return -1;
    222 
    223  if (BUG(!msg))
    224    return -1;
    225 
    226  if (!authdir_mode(options))
    227    return 0;
    228 
    229  if (!authdir_mode_v3(options))
    230    return 0;
    231 
    232  if (options->TestingV3AuthInitialVotingInterval
    233      < MIN_VOTE_INTERVAL_TESTING_INITIAL) {
    234    REJECT("TestingV3AuthInitialVotingInterval is insanely low.");
    235  } else if (((30*60) % options->TestingV3AuthInitialVotingInterval) != 0) {
    236    REJECT("TestingV3AuthInitialVotingInterval does not divide evenly into "
    237           "30 minutes.");
    238  }
    239 
    240  if (options->TestingV3AuthInitialVoteDelay < MIN_VOTE_SECONDS_TESTING) {
    241    REJECT("TestingV3AuthInitialVoteDelay is way too low.");
    242  }
    243 
    244  if (options->TestingV3AuthInitialDistDelay < MIN_DIST_SECONDS_TESTING) {
    245    REJECT("TestingV3AuthInitialDistDelay is way too low.");
    246  }
    247 
    248  if (options->TestingV3AuthInitialVoteDelay +
    249      options->TestingV3AuthInitialDistDelay >=
    250      options->TestingV3AuthInitialVotingInterval) {
    251    REJECT("TestingV3AuthInitialVoteDelay plus TestingV3AuthInitialDistDelay "
    252           "must be less than TestingV3AuthInitialVotingInterval");
    253  }
    254 
    255  if (options->TestingV3AuthVotingStartOffset >
    256      MIN(options->TestingV3AuthInitialVotingInterval,
    257          options->V3AuthVotingInterval)) {
    258    REJECT("TestingV3AuthVotingStartOffset is higher than the voting "
    259           "interval.");
    260  } else if (options->TestingV3AuthVotingStartOffset < 0) {
    261    REJECT("TestingV3AuthVotingStartOffset must be non-negative.");
    262  }
    263 
    264  return 0;
    265 }
    266 
    267 /**
    268 * Return true if changing the configuration from <b>old</b> to <b>new</b>
    269 * affects the timing of the voting subsystem
    270 */
    271 static int
    272 options_transition_affects_dirauth_timing(const or_options_t *old_options,
    273                                          const or_options_t *new_options)
    274 {
    275  tor_assert(old_options);
    276  tor_assert(new_options);
    277 
    278  if (authdir_mode_v3(old_options) != authdir_mode_v3(new_options))
    279    return 1;
    280  if (! authdir_mode_v3(new_options))
    281    return 0;
    282 
    283  YES_IF_CHANGED_INT(V3AuthVotingInterval);
    284  YES_IF_CHANGED_INT(V3AuthVoteDelay);
    285  YES_IF_CHANGED_INT(V3AuthDistDelay);
    286  YES_IF_CHANGED_INT(TestingV3AuthInitialVotingInterval);
    287  YES_IF_CHANGED_INT(TestingV3AuthInitialVoteDelay);
    288  YES_IF_CHANGED_INT(TestingV3AuthInitialDistDelay);
    289  YES_IF_CHANGED_INT(TestingV3AuthVotingStartOffset);
    290 
    291  return 0;
    292 }
    293 
    294 /** Fetch the active option list, and take dirauth actions based on it. All of
    295 * the things we do should survive being done repeatedly.  If present,
    296 * <b>old_options</b> contains the previous value of the options.
    297 *
    298 * Return 0 if all goes well, return -1 if it's time to die.
    299 *
    300 * Note: We haven't moved all the "act on new configuration" logic
    301 * into the options_act* functions yet.  Some is still in do_hup() and other
    302 * places.
    303 */
    304 int
    305 options_act_dirauth(const or_options_t *old_options)
    306 {
    307  const or_options_t *options = get_options();
    308 
    309  /* We may need to reschedule some dirauth stuff if our status changed. */
    310  if (old_options) {
    311    if (options_transition_affects_dirauth_timing(old_options, options)) {
    312      dirauth_sched_recalculate_timing(options, time(NULL));
    313      reschedule_dirvote(options);
    314    }
    315  }
    316 
    317  return 0;
    318 }
    319 
    320 /** Fetch the active option list, and take dirauth mtbf actions based on it.
    321 * All of the things we do should survive being done repeatedly.  If present,
    322 * <b>old_options</b> contains the previous value of the options.
    323 *
    324 * Must be called immediately after a successful or_state_load().
    325 *
    326 * Return 0 if all goes well, return -1 if it's time to die.
    327 *
    328 * Note: We haven't moved all the "act on new configuration" logic
    329 * into the options_act* functions yet.  Some is still in do_hup() and other
    330 * places.
    331 */
    332 int
    333 options_act_dirauth_mtbf(const or_options_t *old_options)
    334 {
    335  (void)old_options;
    336 
    337  const or_options_t *options = get_options();
    338  int running_tor = options->command == CMD_RUN_TOR;
    339 
    340  if (!authdir_mode(options))
    341    return 0;
    342 
    343  /* Load dirauth state */
    344  if (running_tor) {
    345    rep_hist_load_mtbf_data(time(NULL));
    346  }
    347 
    348  return 0;
    349 }
    350 
    351 /** Fetch the active option list, and take dirauth statistics actions based
    352 * on it. All of the things we do should survive being done repeatedly. If
    353 * present, <b>old_options</b> contains the previous value of the options.
    354 *
    355 * Sets <b>*print_notice_out</b> if we enabled stats, and need to print
    356 * a stats log using options_act_relay_stats_msg().
    357 *
    358 * Return 0 if all goes well, return -1 if it's time to die.
    359 *
    360 * Note: We haven't moved all the "act on new configuration" logic
    361 * into the options_act* functions yet.  Some is still in do_hup() and other
    362 * places.
    363 */
    364 int
    365 options_act_dirauth_stats(const or_options_t *old_options,
    366                          bool *print_notice_out)
    367 {
    368  if (BUG(!print_notice_out))
    369    return -1;
    370 
    371  const or_options_t *options = get_options();
    372 
    373  if (authdir_mode_bridge(options)) {
    374    time_t now = time(NULL);
    375    int print_notice = 0;
    376 
    377    if (!old_options || !authdir_mode_bridge(old_options)) {
    378      rep_hist_desc_stats_init(now);
    379      print_notice = 1;
    380    }
    381    if (print_notice)
    382      *print_notice_out = 1;
    383  }
    384 
    385  /* If we used to have statistics enabled but we just disabled them,
    386     stop gathering them.  */
    387  if (old_options && authdir_mode_bridge(old_options) &&
    388      !authdir_mode_bridge(options))
    389    rep_hist_desc_stats_term();
    390 
    391  return 0;
    392 }
    393 
    394 /**
    395 * Make any necessary modifications to a dirauth_options_t that occur
    396 * before validation.  On success return 0; on failure return -1 and
    397 * set *<b>msg_out</b> to a newly allocated error string.
    398 **/
    399 static int
    400 dirauth_options_pre_normalize(void *arg, char **msg_out)
    401 {
    402  dirauth_options_t *options = arg;
    403  (void)msg_out;
    404 
    405  if (!options->RecommendedClientVersions)
    406    options->RecommendedClientVersions =
    407      config_lines_dup(options->RecommendedVersions);
    408  if (!options->RecommendedServerVersions)
    409    options->RecommendedServerVersions =
    410      config_lines_dup(options->RecommendedVersions);
    411 
    412  if (config_ensure_bandwidth_cap(&options->AuthDirFastGuarantee,
    413                           "AuthDirFastGuarantee", msg_out) < 0)
    414    return -1;
    415  if (config_ensure_bandwidth_cap(&options->AuthDirGuardBWGuarantee,
    416                                  "AuthDirGuardBWGuarantee", msg_out) < 0)
    417    return -1;
    418 
    419  return 0;
    420 }
    421 
    422 /**
    423 * Check whether a dirauth_options_t is correct.
    424 *
    425 * On success return 0; on failure return -1 and set *<b>msg_out</b> to a
    426 * newly allocated error string.
    427 **/
    428 static int
    429 dirauth_options_validate(const void *arg, char **msg)
    430 {
    431  const dirauth_options_t *options = arg;
    432  tor_version_t minimal_accepted_server_version, recommended_version;
    433 
    434  if (options->VersioningAuthoritativeDirectory &&
    435      (!options->RecommendedClientVersions ||
    436       !options->RecommendedServerVersions)) {
    437      REJECT("Versioning authoritative dir servers must set "
    438           "Recommended*Versions.");
    439  }
    440 
    441  if (options->AuthDirVoteGuardBwThresholdFraction > 1.0 ||
    442      options->AuthDirVoteGuardBwThresholdFraction < 0.0) {
    443    REJECT("Guard bandwdith threshold fraction is invalid.");
    444  }
    445 
    446  if (tor_version_parse(options->MinimalAcceptedServerVersion,
    447        &minimal_accepted_server_version) != 0) {
    448    REJECT("Invalid MinimalAcceptedServerVersion");
    449  }
    450 
    451  tor_assertf(tor_version_parse(get_short_version(),
    452        &recommended_version) == 0,
    453      "We failed to parse our own version");
    454  if (tor_version_compare(&recommended_version,
    455        &minimal_accepted_server_version) < 0) {
    456    REJECT("MinimalAcceptedServerVersion wants to reject the version "
    457        "this node is running");
    458  }
    459 
    460  char *recommended_versions;
    461  int found_recommended_rejected_version = 0;
    462  /* Call these functions to produce warnings only. */
    463  recommended_versions = format_recommended_version_list(
    464      options->RecommendedClientVersions, 1);
    465  tor_free(recommended_versions);
    466 
    467  recommended_versions = format_recommended_version_list(
    468      options->RecommendedServerVersions, 1);
    469 
    470  smartlist_t *version_sl = smartlist_new();
    471  smartlist_split_string(version_sl, recommended_versions, ",",
    472      SPLIT_SKIP_SPACE, 0);
    473  SMARTLIST_FOREACH_BEGIN(version_sl, const char *, version) {
    474    if (version[0] != '\0' && tor_version_parse(version,
    475          &recommended_version) != 0) {
    476      COMPLAIN("Found unparseable version in RecommendedServerVersions");
    477      continue;
    478    }
    479 
    480    if (tor_version_compare(&recommended_version,
    481          &minimal_accepted_server_version) < 0) {
    482      found_recommended_rejected_version = 1;
    483      break;
    484    }
    485  } SMARTLIST_FOREACH_END(version);
    486 
    487  SMARTLIST_FOREACH(version_sl, char *, version, tor_free(version));
    488  smartlist_free(version_sl);
    489  tor_free(recommended_versions);
    490  if (found_recommended_rejected_version)
    491      REJECT("MinimalAcceptedServerVersion wants to reject a recommended "
    492          "version");
    493 
    494  if (options->TestingAuthDirTimeToLearnReachability > 2*60*60) {
    495    COMPLAIN("TestingAuthDirTimeToLearnReachability is insanely high.");
    496  }
    497 
    498  return 0;
    499 }
    500 
    501 /* Declare the options field table for dirauth_options */
    502 #define CONF_CONTEXT TABLE
    503 #include "feature/dirauth/dirauth_options.inc"
    504 #undef CONF_CONTEXT
    505 
    506 /** Magic number for dirauth_options_t. */
    507 #define DIRAUTH_OPTIONS_MAGIC 0x41757448
    508 
    509 /**
    510 * Declare the configuration options for the dirauth module.
    511 **/
    512 const config_format_t dirauth_options_fmt = {
    513  .size = sizeof(dirauth_options_t),
    514  .magic = { "dirauth_options_t",
    515             DIRAUTH_OPTIONS_MAGIC,
    516             offsetof(dirauth_options_t, magic) },
    517  .vars = dirauth_options_t_vars,
    518 
    519  .pre_normalize_fn = dirauth_options_pre_normalize,
    520  .validate_fn = dirauth_options_validate
    521 };