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