Tor  0.4.7.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"
18 #include "lib/encoding/binascii.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. */
24 static 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. */
54 int
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. */
92 void
93 sr_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. */
114 char *
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. */
130 char *
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. */
145 const 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. */
169 const 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  */
198 sr_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. */
244 time_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. */
289 time_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). */
302 unsigned 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 */
309 unsigned 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:919
Header file for config.c.
#define tor_free(p)
Definition: malloc.h:52
int usable_consensus_flavor(void)
Definition: microdesc.c:1086
Header file for microdesc.c.
time_t voting_sched_get_start_of_interval_after(time_t now, int interval, int offset)
networkstatus_t * networkstatus_get_reasonably_live_consensus(time_t now, int flavor)
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
char * sr_get_previous_for_control(void)
sr_srv_t * sr_parse_srv(const smartlist_t *args)
int get_voting_interval(void)
const sr_srv_t * sr_get_previous(const networkstatus_t *ns)
time_t sr_state_get_start_time_of_previous_protocol_run(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
unsigned int sr_state_get_phase_duration(void)
static char * srv_to_control_string(const sr_srv_t *srv)
const sr_srv_t * sr_get_current(const networkstatus_t *ns)
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:102
int dirauth_sched_get_configured_interval(void)
time_t dirauth_sched_get_cur_valid_after_time(void)
Header file for voting_schedule.c.