Tor 0.4.9.0-alpha-dev
shared_random_client.c
Go to the documentation of this file.
1/* Copyright (c) 2018-2021, The Tor Project, Inc. */
2/* See LICENSE for licensing information */
3
4/**
5 * \file shared_random_client.c
6 * \brief This file contains functions that are from the shared random
7 * subsystem but used by many part of tor. The full feature is built
8 * as part of the dirauth module.
9 **/
10
12
13#include "app/config/config.h"
19
21
22/** Convert a given srv object to a string for the control port. This doesn't
23 * fail and the srv object MUST be valid. */
24static char *
26{
27 char *srv_str;
28 char srv_hash_encoded[SR_SRV_VALUE_BASE64_LEN + 1];
29 tor_assert(srv);
30
31 sr_srv_encode(srv_hash_encoded, sizeof(srv_hash_encoded), srv);
32 tor_asprintf(&srv_str, "%s", srv_hash_encoded);
33 return srv_str;
34}
35
36/**
37 * If we have no consensus and we are not an authority, assume that this is the
38 * voting interval. This can be used while bootstrapping as a relay and we are
39 * asked to initialize HS stats (see rep_hist_hs_stats_init()) */
40#define DEFAULT_NETWORK_VOTING_INTERVAL (3600)
41#define TESTING_DEFAULT_NETWORK_VOTING_INTERVAL (20)
42
43/* This is an unpleasing workaround for tests. Our unit tests assume that we
44 * are scheduling all of our shared random stuff as if we were a directory
45 * authority, but they do not always set V3AuthoritativeDir.
46 */
47#ifdef TOR_UNIT_TESTS
48#define ASSUME_AUTHORITY_SCHEDULING 1
49#else
50#define ASSUME_AUTHORITY_SCHEDULING 0
51#endif
52
53/** Return the voting interval of the tor vote subsystem. */
54int
56{
57 int interval;
58 networkstatus_t *consensus =
61
62 if (consensus) {
63 /* Ideally we have a live consensus and we can just use that. */
64 interval = (int)(consensus->fresh_until - consensus->valid_after);
65 } else if (authdir_mode(get_options()) || ASSUME_AUTHORITY_SCHEDULING) {
66 /* If we don't have a live consensus and we're an authority,
67 * we should believe our own view of what the schedule ought to be. */
69 } else if ((consensus = networkstatus_get_latest_consensus())) {
70 /* If we're a client, then maybe a latest consensus is good enough?
71 * It's better than falling back to the non-consensus case. */
72 interval = (int)(consensus->fresh_until - consensus->valid_after);
73 } else {
74 /* We can reach this as a relay when bootstrapping and we are asked to
75 * initialize HS stats (see rep_hist_hs_stats_init()). */
77 interval = TESTING_DEFAULT_NETWORK_VOTING_INTERVAL;
78 } else {
80 }
81 }
82 tor_assert(interval > 0);
83 return interval;
84}
85
86/*
87 * Public API
88 */
89
90/** Encode the given shared random value and put it in dst. Destination
91 * buffer must be at least SR_SRV_VALUE_BASE64_LEN plus the NULL byte. */
92void
93sr_srv_encode(char *dst, size_t dst_len, const sr_srv_t *srv)
94{
95 int ret;
96 /* Extra byte for the NULL terminated char. */
97 char buf[SR_SRV_VALUE_BASE64_LEN + 1];
98
99 tor_assert(dst);
100 tor_assert(srv);
101 tor_assert(dst_len >= sizeof(buf));
102
103 ret = base64_encode(buf, sizeof(buf), (const char *) srv->value,
104 sizeof(srv->value), 0);
105 /* Always expect the full length without the NULL byte. */
106 tor_assert(ret == (sizeof(buf) - 1));
107 tor_assert(ret <= (int) dst_len);
108 strlcpy(dst, buf, dst_len);
109}
110
111/** Return the current SRV string representation for the control port. Return a
112 * newly allocated string on success containing the value else "" if not found
113 * or if we don't have a valid consensus yet. */
114char *
116{
117 char *srv_str;
119 if (c && c->sr_info.current_srv) {
120 srv_str = srv_to_control_string(c->sr_info.current_srv);
121 } else {
122 srv_str = tor_strdup("");
123 }
124 return srv_str;
125}
126
127/** Return the previous SRV string representation for the control port. Return
128 * a newly allocated string on success containing the value else "" if not
129 * found or if we don't have a valid consensus yet. */
130char *
132{
133 char *srv_str;
135 if (c && c->sr_info.previous_srv) {
136 srv_str = srv_to_control_string(c->sr_info.previous_srv);
137 } else {
138 srv_str = tor_strdup("");
139 }
140 return srv_str;
141}
142
143/** Return current shared random value from the latest consensus. Caller can
144 * NOT keep a reference to the returned pointer. Return NULL if none. */
145const sr_srv_t *
147{
148 const networkstatus_t *consensus;
149
150 /* Use provided ns else get a live one */
151 if (ns) {
152 consensus = ns;
153 } else {
156 }
157 /* Ideally we would never be asked for an SRV without a live consensus. Make
158 * sure this assumption is correct. */
159 tor_assert_nonfatal(consensus);
160
161 if (consensus) {
162 return consensus->sr_info.current_srv;
163 }
164 return NULL;
165}
166
167/** Return previous shared random value from the latest consensus. Caller can
168 * NOT keep a reference to the returned pointer. Return NULL if none. */
169const sr_srv_t *
171{
172 const networkstatus_t *consensus;
173
174 /* Use provided ns else get a live one */
175 if (ns) {
176 consensus = ns;
177 } else {
180 }
181 /* Ideally we would never be asked for an SRV without a live consensus. Make
182 * sure this assumption is correct. */
183 tor_assert_nonfatal(consensus);
184
185 if (consensus) {
186 return consensus->sr_info.previous_srv;
187 }
188 return NULL;
189}
190
191/** Parse a list of arguments from a SRV value either from a vote, consensus
192 * or from our disk state and return a newly allocated srv object. NULL is
193 * returned on error.
194 *
195 * The arguments' order:
196 * num_reveals, value
197 */
198sr_srv_t *
200{
201 char *value;
202 int ok, ret;
203 uint64_t num_reveals;
204 sr_srv_t *srv = NULL;
205
206 tor_assert(args);
207
208 if (smartlist_len(args) < 2) {
209 goto end;
210 }
211
212 /* First argument is the number of reveal values */
213 num_reveals = tor_parse_uint64(smartlist_get(args, 0),
214 10, 0, UINT64_MAX, &ok, NULL);
215 if (!ok) {
216 goto end;
217 }
218 /* Second and last argument is the shared random value it self. */
219 value = smartlist_get(args, 1);
220 if (strlen(value) != SR_SRV_VALUE_BASE64_LEN) {
221 goto end;
222 }
223
224 srv = tor_malloc_zero(sizeof(*srv));
225 srv->num_reveals = num_reveals;
226 /* We subtract one byte from the srclen because the function ignores the
227 * '=' character in the given buffer. This is broken but it's a documented
228 * behavior of the implementation. */
229 ret = base64_decode((char *) srv->value, sizeof(srv->value), value,
231 if (ret != sizeof(srv->value)) {
232 tor_free(srv);
233 srv = NULL;
234 goto end;
235 }
236 end:
237 return srv;
238}
239
240/** Return the start time of the current SR protocol run using the times from
241 * the current consensus. For example, if the latest consensus valid-after is
242 * 23/06/2017 23:00:00 and a full SR protocol run is 24 hours, this function
243 * returns 23/06/2017 00:00:00. */
244time_t
246{
247 int total_rounds = SHARED_RANDOM_N_ROUNDS * SHARED_RANDOM_N_PHASES;
248 int voting_interval = get_voting_interval();
249 time_t beginning_of_curr_round;
250
251 /* This function is not used for voting purposes, so if we have a reasonably
252 * live consensus, use its valid-after as the beginning of the current
253 * round. If we have no consensus but we're an authority, use our own
254 * schedule. Otherwise, try using our view of the voting interval to figure
255 * out when the current round _should_ be starting. */
256 networkstatus_t *ns =
259 if (ns) {
260 beginning_of_curr_round = ns->valid_after;
261 } else if (authdir_mode(get_options()) || ASSUME_AUTHORITY_SCHEDULING) {
262 beginning_of_curr_round = dirauth_sched_get_cur_valid_after_time();
263 } else {
264 /* voting_interval comes from get_voting_interval(), so if we're in
265 * this case as a client, we already tried to get the voting interval
266 * from the latest_consensus and gave a bug warning if we couldn't.
267 *
268 * We wouldn't want to look at the latest consensus's valid_after time,
269 * since that would be out of date. */
270 beginning_of_curr_round = voting_sched_get_start_of_interval_after(
271 approx_time() - voting_interval,
272 voting_interval,
273 0);
274 }
275
276 /* Get current SR protocol round */
277 int curr_round_slot;
278 curr_round_slot = (beginning_of_curr_round / voting_interval) % total_rounds;
279
280 /* Get start time by subtracting the time elapsed from the beginning of the
281 protocol run */
282 time_t time_elapsed_since_start_of_run = curr_round_slot * voting_interval;
283
284 return beginning_of_curr_round - time_elapsed_since_start_of_run;
285}
286
287/** Return the start time of the previous SR protocol run. See
288 * sr_state_get_start_time_of_current_protocol_run() for more details. */
289time_t
291{
292 time_t start_time_of_current_run =
294
295 /* We get the start time of previous protocol run, by getting the start time
296 * of current run and the subtracting a full protocol run from that. */
297 return start_time_of_current_run - sr_state_get_protocol_run_duration();
298}
299
300/** Return the time (in seconds) it takes to complete a full SR protocol phase
301 * (e.g. the commit phase). */
302unsigned int
304{
305 return SHARED_RANDOM_N_ROUNDS * get_voting_interval();
306}
307
308/** Return the time (in seconds) it takes to complete a full SR protocol run */
309unsigned int
311{
312 int total_protocol_rounds = SHARED_RANDOM_N_ROUNDS * SHARED_RANDOM_N_PHASES;
313 return total_protocol_rounds * get_voting_interval();
314}
time_t approx_time(void)
Definition: approx_time.c:32
int authdir_mode(const or_options_t *options)
Definition: authmode.c:25
Header file for directory authority mode.
int base64_decode(char *dest, size_t destlen, const char *src, size_t srclen)
Definition: binascii.c:396
int base64_encode(char *dest, size_t destlen, const char *src, size_t srclen, int flags)
Definition: binascii.c:215
Header for binascii.c.
const or_options_t * get_options(void)
Definition: config.c:944
Header file for config.c.
#define tor_free(p)
Definition: malloc.h:56
int usable_consensus_flavor(void)
Definition: microdesc.c:1086
Header file for microdesc.c.
networkstatus_t * networkstatus_get_reasonably_live_consensus(time_t now, int flavor)
time_t voting_sched_get_start_of_interval_after(time_t now, int interval, int offset)
networkstatus_t * networkstatus_get_latest_consensus(void)
Header file for networkstatus.c.
Networkstatus consensus/vote structure.
uint64_t tor_parse_uint64(const char *s, int base, uint64_t min, uint64_t max, int *ok, char **next)
Definition: parse_int.c:110
int tor_asprintf(char **strp, const char *fmt,...)
Definition: printf.c:75
#define SR_SRV_VALUE_BASE64_LEN
Definition: shared_random.h:48
static char * srv_to_control_string(const sr_srv_t *srv)
int get_voting_interval(void)
time_t sr_state_get_start_time_of_previous_protocol_run(void)
char * sr_get_previous_for_control(void)
unsigned int sr_state_get_protocol_run_duration(void)
void sr_srv_encode(char *dst, size_t dst_len, const sr_srv_t *srv)
char * sr_get_current_for_control(void)
time_t sr_state_get_start_time_of_current_protocol_run(void)
#define DEFAULT_NETWORK_VOTING_INTERVAL
sr_srv_t * sr_parse_srv(const smartlist_t *args)
const sr_srv_t * sr_get_current(const networkstatus_t *ns)
const sr_srv_t * sr_get_previous(const networkstatus_t *ns)
unsigned int sr_state_get_phase_duration(void)
Header file for shared_random_client.c.
networkstatus_sr_info_t sr_info
uint64_t num_reveals
Definition: shared_random.h:64
uint8_t value[DIGEST256_LEN]
Definition: shared_random.h:66
#define tor_assert(expr)
Definition: util_bug.h:103
int dirauth_sched_get_configured_interval(void)
time_t dirauth_sched_get_cur_valid_after_time(void)
Header file for voting_schedule.c.