Line data Source code
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 : 11 : #include "feature/hs_common/shared_random_client.h" 12 : 13 : #include "app/config/config.h" 14 : #include "feature/dirauth/authmode.h" 15 : #include "feature/dirauth/voting_schedule.h" 16 : #include "feature/nodelist/microdesc.h" 17 : #include "feature/nodelist/networkstatus.h" 18 : #include "lib/encoding/binascii.h" 19 : 20 : #include "feature/nodelist/networkstatus_st.h" 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 * 25 0 : srv_to_control_string(const sr_srv_t *srv) 26 : { 27 0 : char *srv_str; 28 0 : char srv_hash_encoded[SR_SRV_VALUE_BASE64_LEN + 1]; 29 0 : tor_assert(srv); 30 : 31 0 : sr_srv_encode(srv_hash_encoded, sizeof(srv_hash_encoded), srv); 32 0 : tor_asprintf(&srv_str, "%s", srv_hash_encoded); 33 0 : 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 55 69661 : get_voting_interval(void) 56 : { 57 69661 : int interval; 58 69661 : networkstatus_t *consensus = 59 69661 : networkstatus_get_reasonably_live_consensus(time(NULL), 60 : usable_consensus_flavor()); 61 : 62 69661 : if (consensus) { 63 : /* Ideally we have a live consensus and we can just use that. */ 64 69443 : interval = (int)(consensus->fresh_until - consensus->valid_after); 65 218 : } 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. */ 68 218 : interval = dirauth_sched_get_configured_interval(); 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()). */ 76 : if (get_options()->TestingTorNetwork) { 77 : interval = TESTING_DEFAULT_NETWORK_VOTING_INTERVAL; 78 : } else { 79 : interval = DEFAULT_NETWORK_VOTING_INTERVAL; 80 : } 81 : } 82 69661 : tor_assert(interval > 0); 83 69661 : 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 84 : sr_srv_encode(char *dst, size_t dst_len, const sr_srv_t *srv) 94 : { 95 84 : int ret; 96 : /* Extra byte for the NULL terminated char. */ 97 84 : char buf[SR_SRV_VALUE_BASE64_LEN + 1]; 98 : 99 84 : tor_assert(dst); 100 84 : tor_assert(srv); 101 84 : tor_assert(dst_len >= sizeof(buf)); 102 : 103 84 : 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 84 : tor_assert(ret == (sizeof(buf) - 1)); 107 84 : tor_assert(ret <= (int) dst_len); 108 84 : strlcpy(dst, buf, dst_len); 109 84 : } 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 * 115 0 : sr_get_current_for_control(void) 116 : { 117 0 : char *srv_str; 118 0 : const networkstatus_t *c = networkstatus_get_latest_consensus(); 119 0 : if (c && c->sr_info.current_srv) { 120 0 : srv_str = srv_to_control_string(c->sr_info.current_srv); 121 : } else { 122 0 : srv_str = tor_strdup(""); 123 : } 124 0 : 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 * 131 0 : sr_get_previous_for_control(void) 132 : { 133 0 : char *srv_str; 134 0 : const networkstatus_t *c = networkstatus_get_latest_consensus(); 135 0 : if (c && c->sr_info.previous_srv) { 136 0 : srv_str = srv_to_control_string(c->sr_info.previous_srv); 137 : } else { 138 0 : srv_str = tor_strdup(""); 139 : } 140 0 : 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 * 146 9021 : sr_get_current(const networkstatus_t *ns) 147 : { 148 9021 : const networkstatus_t *consensus; 149 : 150 : /* Use provided ns else get a live one */ 151 9021 : if (ns) { 152 : consensus = ns; 153 : } else { 154 0 : consensus = networkstatus_get_reasonably_live_consensus(approx_time(), 155 : usable_consensus_flavor()); 156 : } 157 : /* Ideally we would never be asked for an SRV without a live consensus. Make 158 : * sure this assumption is correct. */ 159 9021 : tor_assert_nonfatal(consensus); 160 : 161 9021 : if (consensus) { 162 9021 : 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 * 170 9042 : sr_get_previous(const networkstatus_t *ns) 171 : { 172 9042 : const networkstatus_t *consensus; 173 : 174 : /* Use provided ns else get a live one */ 175 9042 : if (ns) { 176 : consensus = ns; 177 : } else { 178 0 : consensus = networkstatus_get_reasonably_live_consensus(approx_time(), 179 : usable_consensus_flavor()); 180 : } 181 : /* Ideally we would never be asked for an SRV without a live consensus. Make 182 : * sure this assumption is correct. */ 183 9042 : tor_assert_nonfatal(consensus); 184 : 185 9042 : if (consensus) { 186 9042 : 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 * 199 16 : sr_parse_srv(const smartlist_t *args) 200 : { 201 16 : char *value; 202 16 : int ok, ret; 203 16 : uint64_t num_reveals; 204 16 : sr_srv_t *srv = NULL; 205 : 206 16 : tor_assert(args); 207 : 208 16 : if (smartlist_len(args) < 2) { 209 0 : goto end; 210 : } 211 : 212 : /* First argument is the number of reveal values */ 213 16 : num_reveals = tor_parse_uint64(smartlist_get(args, 0), 214 : 10, 0, UINT64_MAX, &ok, NULL); 215 16 : if (!ok) { 216 9 : goto end; 217 : } 218 : /* Second and last argument is the shared random value it self. */ 219 7 : value = smartlist_get(args, 1); 220 7 : if (strlen(value) != SR_SRV_VALUE_BASE64_LEN) { 221 3 : goto end; 222 : } 223 : 224 4 : srv = tor_malloc_zero(sizeof(*srv)); 225 4 : 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 4 : ret = base64_decode((char *) srv->value, sizeof(srv->value), value, 230 : SR_SRV_VALUE_BASE64_LEN - 1); 231 4 : if (ret != sizeof(srv->value)) { 232 1 : tor_free(srv); 233 1 : srv = NULL; 234 1 : goto end; 235 : } 236 3 : end: 237 16 : 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 245 18103 : sr_state_get_start_time_of_current_protocol_run(void) 246 : { 247 18103 : int total_rounds = SHARED_RANDOM_N_ROUNDS * SHARED_RANDOM_N_PHASES; 248 18103 : int voting_interval = get_voting_interval(); 249 18103 : 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 18103 : networkstatus_t *ns = 257 18103 : networkstatus_get_reasonably_live_consensus(approx_time(), 258 : usable_consensus_flavor()); 259 18103 : if (ns) { 260 18084 : beginning_of_curr_round = ns->valid_after; 261 19 : } else if (authdir_mode(get_options()) || ASSUME_AUTHORITY_SCHEDULING) { 262 19 : 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 18103 : int curr_round_slot; 278 18103 : 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 18103 : time_t time_elapsed_since_start_of_run = curr_round_slot * voting_interval; 283 : 284 18103 : 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 290 0 : sr_state_get_start_time_of_previous_protocol_run(void) 291 : { 292 0 : time_t start_time_of_current_run = 293 0 : sr_state_get_start_time_of_current_protocol_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 0 : 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 303 51457 : sr_state_get_phase_duration(void) 304 : { 305 51457 : 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 310 12 : sr_state_get_protocol_run_duration(void) 311 : { 312 12 : int total_protocol_rounds = SHARED_RANDOM_N_ROUNDS * SHARED_RANDOM_N_PHASES; 313 12 : return total_protocol_rounds * get_voting_interval(); 314 : }