tor  0.4.2.1-alpha-dev
shared_random_client.c
Go to the documentation of this file.
1 /* Copyright (c) 2018-2019, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
3 
11 #define SHARED_RANDOM_CLIENT_PRIVATE
13 
14 #include "app/config/config.h"
17 #include "lib/encoding/binascii.h"
18 
19 #include "feature/nodelist/networkstatus_st.h"
20 
21 /* Convert a given srv object to a string for the control port. This doesn't
22  * fail and the srv object MUST be valid. */
23 static char *
24 srv_to_control_string(const sr_srv_t *srv)
25 {
26  char *srv_str;
27  char srv_hash_encoded[SR_SRV_VALUE_BASE64_LEN + 1];
28  tor_assert(srv);
29 
30  sr_srv_encode(srv_hash_encoded, sizeof(srv_hash_encoded), srv);
31  tor_asprintf(&srv_str, "%s", srv_hash_encoded);
32  return srv_str;
33 }
34 
35 /* Return the voting interval of the tor vote subsystem. */
36 int
37 get_voting_interval(void)
38 {
39  int interval;
40  networkstatus_t *consensus = networkstatus_get_live_consensus(time(NULL));
41 
42  if (consensus) {
43  interval = (int)(consensus->fresh_until - consensus->valid_after);
44  } else {
45  /* Same for both a testing and real network. We voluntarily ignore the
46  * InitialVotingInterval since it complexifies things and it doesn't
47  * affect the SR protocol. */
48  interval = get_options()->V3AuthVotingInterval;
49  }
50  tor_assert(interval > 0);
51  return interval;
52 }
53 
54 /* Given the current consensus, return the start time of the current round of
55  * the SR protocol. For example, if it's 23:47:08, the current round thus
56  * started at 23:47:00 for a voting interval of 10 seconds.
57  *
58  * This function uses the consensus voting schedule to derive its results,
59  * instead of the actual consensus we are currently using, so it should be used
60  * for voting purposes. */
61 time_t
62 get_start_time_of_current_round(void)
63 {
64  const or_options_t *options = get_options();
65  int voting_interval = get_voting_interval();
66  /* First, get the start time of the next round */
67  time_t next_start = voting_schedule_get_next_valid_after_time();
68  /* Now roll back next_start by a voting interval to find the start time of
69  the current round. */
71  next_start - voting_interval - 1,
72  voting_interval,
74  return curr_start;
75 }
76 
77 /*
78  * Public API
79  */
80 
81 /* Encode the given shared random value and put it in dst. Destination
82  * buffer must be at least SR_SRV_VALUE_BASE64_LEN plus the NULL byte. */
83 void
84 sr_srv_encode(char *dst, size_t dst_len, const sr_srv_t *srv)
85 {
86  int ret;
87  /* Extra byte for the NULL terminated char. */
88  char buf[SR_SRV_VALUE_BASE64_LEN + 1];
89 
90  tor_assert(dst);
91  tor_assert(srv);
92  tor_assert(dst_len >= sizeof(buf));
93 
94  ret = base64_encode(buf, sizeof(buf), (const char *) srv->value,
95  sizeof(srv->value), 0);
96  /* Always expect the full length without the NULL byte. */
97  tor_assert(ret == (sizeof(buf) - 1));
98  tor_assert(ret <= (int) dst_len);
99  strlcpy(dst, buf, dst_len);
100 }
101 
102 /* Return the current SRV string representation for the control port. Return a
103  * newly allocated string on success containing the value else "" if not found
104  * or if we don't have a valid consensus yet. */
105 char *
106 sr_get_current_for_control(void)
107 {
108  char *srv_str;
109  const networkstatus_t *c = networkstatus_get_latest_consensus();
110  if (c && c->sr_info.current_srv) {
111  srv_str = srv_to_control_string(c->sr_info.current_srv);
112  } else {
113  srv_str = tor_strdup("");
114  }
115  return srv_str;
116 }
117 
118 /* Return the previous SRV string representation for the control port. Return
119  * a newly allocated string on success containing the value else "" if not
120  * found or if we don't have a valid consensus yet. */
121 char *
122 sr_get_previous_for_control(void)
123 {
124  char *srv_str;
125  const networkstatus_t *c = networkstatus_get_latest_consensus();
126  if (c && c->sr_info.previous_srv) {
127  srv_str = srv_to_control_string(c->sr_info.previous_srv);
128  } else {
129  srv_str = tor_strdup("");
130  }
131  return srv_str;
132 }
133 
134 /* Return current shared random value from the latest consensus. Caller can
135  * NOT keep a reference to the returned pointer. Return NULL if none. */
136 const sr_srv_t *
137 sr_get_current(const networkstatus_t *ns)
138 {
139  const networkstatus_t *consensus;
140 
141  /* Use provided ns else get a live one */
142  if (ns) {
143  consensus = ns;
144  } else {
145  consensus = networkstatus_get_live_consensus(approx_time());
146  }
147  /* Ideally we would never be asked for an SRV without a live consensus. Make
148  * sure this assumption is correct. */
149  tor_assert_nonfatal(consensus);
150 
151  if (consensus) {
152  return consensus->sr_info.current_srv;
153  }
154  return NULL;
155 }
156 
157 /* Return previous shared random value from the latest consensus. Caller can
158  * NOT keep a reference to the returned pointer. Return NULL if none. */
159 const sr_srv_t *
160 sr_get_previous(const networkstatus_t *ns)
161 {
162  const networkstatus_t *consensus;
163 
164  /* Use provided ns else get a live one */
165  if (ns) {
166  consensus = ns;
167  } else {
168  consensus = networkstatus_get_live_consensus(approx_time());
169  }
170  /* Ideally we would never be asked for an SRV without a live consensus. Make
171  * sure this assumption is correct. */
172  tor_assert_nonfatal(consensus);
173 
174  if (consensus) {
175  return consensus->sr_info.previous_srv;
176  }
177  return NULL;
178 }
179 
180 /* Parse a list of arguments from a SRV value either from a vote, consensus
181  * or from our disk state and return a newly allocated srv object. NULL is
182  * returned on error.
183  *
184  * The arguments' order:
185  * num_reveals, value
186  */
187 sr_srv_t *
188 sr_parse_srv(const smartlist_t *args)
189 {
190  char *value;
191  int ok, ret;
192  uint64_t num_reveals;
193  sr_srv_t *srv = NULL;
194 
195  tor_assert(args);
196 
197  if (smartlist_len(args) < 2) {
198  goto end;
199  }
200 
201  /* First argument is the number of reveal values */
202  num_reveals = tor_parse_uint64(smartlist_get(args, 0),
203  10, 0, UINT64_MAX, &ok, NULL);
204  if (!ok) {
205  goto end;
206  }
207  /* Second and last argument is the shared random value it self. */
208  value = smartlist_get(args, 1);
209  if (strlen(value) != SR_SRV_VALUE_BASE64_LEN) {
210  goto end;
211  }
212 
213  srv = tor_malloc_zero(sizeof(*srv));
214  srv->num_reveals = num_reveals;
215  /* We subtract one byte from the srclen because the function ignores the
216  * '=' character in the given buffer. This is broken but it's a documented
217  * behavior of the implementation. */
218  ret = base64_decode((char *) srv->value, sizeof(srv->value), value,
219  SR_SRV_VALUE_BASE64_LEN - 1);
220  if (ret != sizeof(srv->value)) {
221  tor_free(srv);
222  srv = NULL;
223  goto end;
224  }
225  end:
226  return srv;
227 }
228 
233 time_t
235 {
236  int total_rounds = SHARED_RANDOM_N_ROUNDS * SHARED_RANDOM_N_PHASES;
237  int voting_interval = get_voting_interval();
238  time_t beginning_of_curr_round;
239 
240  /* This function is not used for voting purposes, so if we have a live
241  consensus, use its valid-after as the beginning of the current round,
242  otherwise resort to the voting schedule which should always exist. */
243  networkstatus_t *ns = networkstatus_get_live_consensus(approx_time());
244  if (ns) {
245  beginning_of_curr_round = ns->valid_after;
246  } else {
247  beginning_of_curr_round = get_start_time_of_current_round();
248  }
249 
250  /* Get current SR protocol round */
251  int curr_round_slot;
252  curr_round_slot = (beginning_of_curr_round / voting_interval) % total_rounds;
253 
254  /* Get start time by subtracting the time elapsed from the beginning of the
255  protocol run */
256  time_t time_elapsed_since_start_of_run = curr_round_slot * voting_interval;
257 
258  log_debug(LD_GENERAL, "Current SRV proto run: Start of current round: %u. "
259  "Time elapsed: %u (%d)", (unsigned) beginning_of_curr_round,
260  (unsigned) time_elapsed_since_start_of_run, voting_interval);
261 
262  return beginning_of_curr_round - time_elapsed_since_start_of_run;
263 }
264 
267 time_t
269 {
270  time_t start_time_of_current_run =
272 
273  /* We get the start time of previous protocol run, by getting the start time
274  * of current run and the subtracting a full protocol run from that. */
275  return start_time_of_current_run - sr_state_get_protocol_run_duration();
276 }
277 
280 unsigned int
282 {
283  return SHARED_RANDOM_N_ROUNDS * get_voting_interval();
284 }
285 
287 unsigned int
289 {
290  int total_protocol_rounds = SHARED_RANDOM_N_ROUNDS * SHARED_RANDOM_N_PHASES;
291  return total_protocol_rounds * get_voting_interval();
292 }
293 
networkstatus_sr_info_t sr_info
uint64_t tor_parse_uint64(const char *s, int base, uint64_t min, uint64_t max, int *ok, char **next)
Definition: parse_int.c:107
#define LD_GENERAL
Definition: log.h:60
time_t sr_state_get_start_time_of_current_protocol_run(void)
Header file for config.c.
#define tor_free(p)
Definition: malloc.h:52
time_t sr_state_get_start_time_of_previous_protocol_run(void)
time_t voting_schedule_get_start_of_next_interval(time_t now, int interval, int offset)
int base64_encode(char *dest, size_t destlen, const char *src, size_t srclen, int flags)
Definition: binascii.c:215
tor_assert(buffer)
int tor_asprintf(char **strp, const char *fmt,...)
Definition: printf.c:75
unsigned int sr_state_get_protocol_run_duration(void)
Header for binascii.c.
Header file for shared_random_client.c.
Header file for voting_schedule.c.
unsigned int sr_state_get_phase_duration(void)
int base64_decode(char *dest, size_t destlen, const char *src, size_t srclen)
Definition: binascii.c:396
time_t approx_time(void)
Definition: approx_time.c:32
int TestingV3AuthVotingStartOffset
Header file for networkstatus.c.