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
dirauth_should_reject_requests_under_load(void)53 dirauth_should_reject_requests_under_load(void)
54 {
55   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
options_validate_dirauth_mode(const or_options_t * old_options,or_options_t * options,char ** msg)66 options_validate_dirauth_mode(const or_options_t *old_options,
67                               or_options_t *options,
68                               char **msg)
69 {
70   if (BUG(!options))
71     return -1;
72 
73   if (BUG(!msg))
74     return -1;
75 
76   if (!authdir_mode(options))
77     return 0;
78 
79   /* confirm that our address isn't broken, so we can complain now */
80   tor_addr_t tmp;
81   if (!find_my_address(options, AF_INET, LOG_WARN, &tmp, NULL, NULL))
82     REJECT("Failed to resolve/guess local address. See logs for details.");
83 
84   if (!options->ContactInfo && !options->TestingTorNetwork)
85     REJECT("Authoritative directory servers must set ContactInfo");
86 
87   if (options->UseEntryGuards) {
88     log_info(LD_CONFIG, "Authoritative directory servers can't set "
89              "UseEntryGuards. Disabling.");
90     options->UseEntryGuards = 0;
91   }
92   if (!options->DownloadExtraInfo && authdir_mode_v3(options)) {
93     log_info(LD_CONFIG, "Authoritative directories always try to download "
94              "extra-info documents. Setting DownloadExtraInfo.");
95     options->DownloadExtraInfo = 1;
96   }
97   if (!(options->BridgeAuthoritativeDir ||
98         options->V3AuthoritativeDir))
99     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   if (options->V3BandwidthsFile && !old_options) {
104     dirserv_read_measured_bandwidths(options->V3BandwidthsFile, NULL, NULL,
105                                      NULL);
106   }
107   /* same for guardfraction file */
108   if (options->GuardfractionFile && !old_options) {
109     dirserv_read_guardfraction_file(options->GuardfractionFile, NULL);
110   }
111 
112   if (!options->DirPort_set)
113     REJECT("Running as authoritative directory, but no DirPort set.");
114 
115   if (!options->ORPort_set)
116     REJECT("Running as authoritative directory, but no ORPort set.");
117 
118   if (options->ClientOnly)
119     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
options_validate_dirauth_schedule(const or_options_t * old_options,or_options_t * options,char ** msg)132 options_validate_dirauth_schedule(const or_options_t *old_options,
133                                   or_options_t *options,
134                                   char **msg)
135 {
136   (void)old_options;
137 
138   if (BUG(!options))
139     return -1;
140 
141   if (BUG(!msg))
142     return -1;
143 
144   if (!authdir_mode_v3(options))
145     return 0;
146 
147   if (options->V3AuthVoteDelay + options->V3AuthDistDelay >=
148       options->V3AuthVotingInterval/2) {
149     REJECT("V3AuthVoteDelay plus V3AuthDistDelay must be less than half "
150            "V3AuthVotingInterval");
151   }
152 
153   if (options->V3AuthVoteDelay < MIN_VOTE_SECONDS) {
154     if (options->TestingTorNetwork) {
155       if (options->V3AuthVoteDelay < MIN_VOTE_SECONDS_TESTING) {
156         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       REJECT("V3AuthVoteDelay is way too low.");
163     }
164   }
165 
166   if (options->V3AuthDistDelay < MIN_DIST_SECONDS) {
167     if (options->TestingTorNetwork) {
168       if (options->V3AuthDistDelay < MIN_DIST_SECONDS_TESTING) {
169         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       REJECT("V3AuthDistDelay is way too low.");
176     }
177   }
178 
179   if (options->V3AuthNIntervalsValid < 2)
180     REJECT("V3AuthNIntervalsValid must be at least 2.");
181 
182   if (options->V3AuthVotingInterval < MIN_VOTE_INTERVAL) {
183     if (options->TestingTorNetwork) {
184       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         COMPLAIN("V3AuthVotingInterval is very low. "
189                  "This may lead to failure to synchronise for a consensus.");
190       }
191     } else {
192       REJECT("V3AuthVotingInterval is insanely low.");
193     }
194   } else if (options->V3AuthVotingInterval > 24*60*60) {
195     REJECT("V3AuthVotingInterval is insanely high.");
196   } else if (((24*60*60) % options->V3AuthVotingInterval) != 0) {
197     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
options_validate_dirauth_testing(const or_options_t * old_options,or_options_t * options,char ** msg)211 options_validate_dirauth_testing(const or_options_t *old_options,
212                                  or_options_t *options,
213                                  char **msg)
214 {
215   (void)old_options;
216 
217   if (BUG(!options))
218     return -1;
219 
220   if (BUG(!msg))
221     return -1;
222 
223   if (!authdir_mode(options))
224     return 0;
225 
226   if (!authdir_mode_v3(options))
227     return 0;
228 
229   if (options->TestingV3AuthInitialVotingInterval
230       < MIN_VOTE_INTERVAL_TESTING_INITIAL) {
231     REJECT("TestingV3AuthInitialVotingInterval is insanely low.");
232   } else if (((30*60) % options->TestingV3AuthInitialVotingInterval) != 0) {
233     REJECT("TestingV3AuthInitialVotingInterval does not divide evenly into "
234            "30 minutes.");
235   }
236 
237   if (options->TestingV3AuthInitialVoteDelay < MIN_VOTE_SECONDS_TESTING) {
238     REJECT("TestingV3AuthInitialVoteDelay is way too low.");
239   }
240 
241   if (options->TestingV3AuthInitialDistDelay < MIN_DIST_SECONDS_TESTING) {
242     REJECT("TestingV3AuthInitialDistDelay is way too low.");
243   }
244 
245   if (options->TestingV3AuthInitialVoteDelay +
246       options->TestingV3AuthInitialDistDelay >=
247       options->TestingV3AuthInitialVotingInterval) {
248     REJECT("TestingV3AuthInitialVoteDelay plus TestingV3AuthInitialDistDelay "
249            "must be less than TestingV3AuthInitialVotingInterval");
250   }
251 
252   if (options->TestingV3AuthVotingStartOffset >
253       MIN(options->TestingV3AuthInitialVotingInterval,
254           options->V3AuthVotingInterval)) {
255     REJECT("TestingV3AuthVotingStartOffset is higher than the voting "
256            "interval.");
257   } else if (options->TestingV3AuthVotingStartOffset < 0) {
258     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
options_transition_affects_dirauth_timing(const or_options_t * old_options,const or_options_t * new_options)269 options_transition_affects_dirauth_timing(const or_options_t *old_options,
270                                           const or_options_t *new_options)
271 {
272   tor_assert(old_options);
273   tor_assert(new_options);
274 
275   if (authdir_mode_v3(old_options) != authdir_mode_v3(new_options))
276     return 1;
277   if (! authdir_mode_v3(new_options))
278     return 0;
279 
280   YES_IF_CHANGED_INT(V3AuthVotingInterval);
281   YES_IF_CHANGED_INT(V3AuthVoteDelay);
282   YES_IF_CHANGED_INT(V3AuthDistDelay);
283   YES_IF_CHANGED_INT(TestingV3AuthInitialVotingInterval);
284   YES_IF_CHANGED_INT(TestingV3AuthInitialVoteDelay);
285   YES_IF_CHANGED_INT(TestingV3AuthInitialDistDelay);
286   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
options_act_dirauth(const or_options_t * old_options)302 options_act_dirauth(const or_options_t *old_options)
303 {
304   const or_options_t *options = get_options();
305 
306   /* We may need to reschedule some dirauth stuff if our status changed. */
307   if (old_options) {
308     if (options_transition_affects_dirauth_timing(old_options, options)) {
309       dirauth_sched_recalculate_timing(options, time(NULL));
310       reschedule_dirvote(options);
311     }
312   }
313 
314   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
options_act_dirauth_mtbf(const or_options_t * old_options)330 options_act_dirauth_mtbf(const or_options_t *old_options)
331 {
332   (void)old_options;
333 
334   const or_options_t *options = get_options();
335   int running_tor = options->command == CMD_RUN_TOR;
336 
337   if (!authdir_mode(options))
338     return 0;
339 
340   /* Load dirauth state */
341   if (running_tor) {
342     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
options_act_dirauth_stats(const or_options_t * old_options,bool * print_notice_out)362 options_act_dirauth_stats(const or_options_t *old_options,
363                           bool *print_notice_out)
364 {
365   if (BUG(!print_notice_out))
366     return -1;
367 
368   const or_options_t *options = get_options();
369 
370   if (authdir_mode_bridge(options)) {
371     time_t now = time(NULL);
372     int print_notice = 0;
373 
374     if (!old_options || !authdir_mode_bridge(old_options)) {
375       rep_hist_desc_stats_init(now);
376       print_notice = 1;
377     }
378     if (print_notice)
379       *print_notice_out = 1;
380   }
381 
382   /* If we used to have statistics enabled but we just disabled them,
383      stop gathering them.  */
384   if (old_options && authdir_mode_bridge(old_options) &&
385       !authdir_mode_bridge(options))
386     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
dirauth_options_pre_normalize(void * arg,char ** msg_out)397 dirauth_options_pre_normalize(void *arg, char **msg_out)
398 {
399   dirauth_options_t *options = arg;
400   (void)msg_out;
401 
402   if (!options->RecommendedClientVersions)
403     options->RecommendedClientVersions =
404       config_lines_dup(options->RecommendedVersions);
405   if (!options->RecommendedServerVersions)
406     options->RecommendedServerVersions =
407       config_lines_dup(options->RecommendedVersions);
408 
409   if (config_ensure_bandwidth_cap(&options->AuthDirFastGuarantee,
410                            "AuthDirFastGuarantee", msg_out) < 0)
411     return -1;
412   if (config_ensure_bandwidth_cap(&options->AuthDirGuardBWGuarantee,
413                                   "AuthDirGuardBWGuarantee", msg_out) < 0)
414     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
dirauth_options_validate(const void * arg,char ** msg)426 dirauth_options_validate(const void *arg, char **msg)
427 {
428   const dirauth_options_t *options = arg;
429 
430   if (options->VersioningAuthoritativeDirectory &&
431       (!options->RecommendedClientVersions ||
432        !options->RecommendedServerVersions)) {
433       REJECT("Versioning authoritative dir servers must set "
434            "Recommended*Versions.");
435   }
436 
437   char *t;
438   /* Call these functions to produce warnings only. */
439   t = format_recommended_version_list(options->RecommendedClientVersions, 1);
440   tor_free(t);
441   t = format_recommended_version_list(options->RecommendedServerVersions, 1);
442   tor_free(t);
443 
444   if (options->TestingAuthDirTimeToLearnReachability > 2*60*60) {
445     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 };
472