LCOV - code coverage report
Current view: top level - feature/dirauth - dirauth_config.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 117 151 77.5 %
Date: 2021-11-24 03:28:48 Functions: 9 10 90.0 %

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

Generated by: LCOV version 1.14