/src/tor/src/feature/dirclient/dirclient.c
Line | Count | Source |
1 | | /* Copyright (c) 2001-2004, Roger Dingledine. |
2 | | * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. |
3 | | * Copyright (c) 2007-2021, The Tor Project, Inc. */ |
4 | | /* See LICENSE for licensing information */ |
5 | | |
6 | | /** |
7 | | * @file dirclient.c |
8 | | * @brief Download directory information |
9 | | **/ |
10 | | |
11 | | #define DIRCLIENT_PRIVATE |
12 | | |
13 | | #include "core/or/or.h" |
14 | | |
15 | | #include "app/config/config.h" |
16 | | #include "core/mainloop/connection.h" |
17 | | #include "core/mainloop/mainloop.h" |
18 | | #include "core/or/connection_edge.h" |
19 | | #include "core/or/policies.h" |
20 | | #include "feature/client/bridges.h" |
21 | | #include "feature/client/entrynodes.h" |
22 | | #include "feature/control/control_events.h" |
23 | | #include "feature/dirauth/authmode.h" |
24 | | #include "feature/dirclient/dirclient.h" |
25 | | #include "feature/dirauth/dirvote.h" |
26 | | #include "feature/dirauth/shared_random.h" |
27 | | #include "feature/dircache/dirserv.h" |
28 | | #include "feature/dirclient/dirclient.h" |
29 | | #include "feature/dirclient/dirclient_modes.h" |
30 | | #include "feature/dirclient/dlstatus.h" |
31 | | #include "feature/dircommon/consdiff.h" |
32 | | #include "feature/dircommon/directory.h" |
33 | | #include "feature/dircommon/fp_pair.h" |
34 | | #include "feature/hs/hs_cache.h" |
35 | | #include "feature/hs/hs_client.h" |
36 | | #include "feature/hs/hs_control.h" |
37 | | #include "feature/nodelist/authcert.h" |
38 | | #include "feature/nodelist/describe.h" |
39 | | #include "feature/nodelist/dirlist.h" |
40 | | #include "feature/nodelist/microdesc.h" |
41 | | #include "feature/nodelist/networkstatus.h" |
42 | | #include "feature/nodelist/node_select.h" |
43 | | #include "feature/nodelist/nodelist.h" |
44 | | #include "feature/nodelist/routerinfo.h" |
45 | | #include "feature/nodelist/routerlist.h" |
46 | | #include "feature/nodelist/routerset.h" |
47 | | #include "feature/relay/relay_find_addr.h" |
48 | | #include "feature/relay/routermode.h" |
49 | | #include "feature/relay/selftest.h" |
50 | | #include "feature/rend/rendcommon.h" |
51 | | #include "feature/stats/predict_ports.h" |
52 | | |
53 | | #include "lib/cc/ctassert.h" |
54 | | #include "lib/compress/compress.h" |
55 | | #include "lib/crypt_ops/crypto_format.h" |
56 | | #include "lib/crypt_ops/crypto_util.h" |
57 | | #include "lib/encoding/confline.h" |
58 | | #include "lib/err/backtrace.h" |
59 | | |
60 | | #include "core/or/entry_connection_st.h" |
61 | | #include "feature/dircache/cached_dir_st.h" |
62 | | #include "feature/dirclient/dir_server_st.h" |
63 | | #include "feature/dircommon/dir_connection_st.h" |
64 | | #include "feature/nodelist/networkstatus_st.h" |
65 | | #include "feature/nodelist/node_st.h" |
66 | | #include "feature/nodelist/routerinfo_st.h" |
67 | | |
68 | | /** Maximum size, in bytes, for any directory object that we've downloaded. */ |
69 | 0 | #define MAX_DIR_DL_SIZE ((1<<24)-1) /* 16 MB - 1 */ |
70 | | |
71 | | /** How far in the future do we allow a directory server to tell us it is |
72 | | * before deciding that one of us has the wrong time? */ |
73 | 0 | #define ALLOW_DIRECTORY_TIME_SKEW (30*60) |
74 | | |
75 | | static int body_is_plausible(const char *body, size_t body_len, int purpose); |
76 | | static void connection_dir_download_routerdesc_failed(dir_connection_t *conn); |
77 | | static void connection_dir_bridge_routerdesc_failed(dir_connection_t *conn); |
78 | | static void connection_dir_download_cert_failed( |
79 | | dir_connection_t *conn, int status_code); |
80 | | static void connection_dir_retry_bridges(smartlist_t *descs); |
81 | | static void dir_routerdesc_download_failed(smartlist_t *failed, |
82 | | int status_code, |
83 | | int router_purpose, |
84 | | int was_extrainfo, |
85 | | int was_descriptor_digests); |
86 | | static void dir_microdesc_download_failed(smartlist_t *failed, |
87 | | int status_code, |
88 | | const char *dir_id); |
89 | | static void directory_send_command(dir_connection_t *conn, |
90 | | const int direct, |
91 | | const directory_request_t *req); |
92 | | static void connection_dir_close_consensus_fetches( |
93 | | dir_connection_t *except_this_one, const char *resource); |
94 | | |
95 | | /** Return a string describing a given directory connection purpose. */ |
96 | | STATIC const char * |
97 | | dir_conn_purpose_to_string(int purpose) |
98 | 0 | { |
99 | 0 | switch (purpose) |
100 | 0 | { |
101 | 0 | case DIR_PURPOSE_UPLOAD_DIR: |
102 | 0 | return "server descriptor upload"; |
103 | 0 | case DIR_PURPOSE_UPLOAD_VOTE: |
104 | 0 | return "consensus vote upload"; |
105 | 0 | case DIR_PURPOSE_UPLOAD_SIGNATURES: |
106 | 0 | return "consensus signature upload"; |
107 | 0 | case DIR_PURPOSE_FETCH_SERVERDESC: |
108 | 0 | return "server descriptor fetch"; |
109 | 0 | case DIR_PURPOSE_FETCH_EXTRAINFO: |
110 | 0 | return "extra-info fetch"; |
111 | 0 | case DIR_PURPOSE_FETCH_CONSENSUS: |
112 | 0 | return "consensus network-status fetch"; |
113 | 0 | case DIR_PURPOSE_FETCH_CERTIFICATE: |
114 | 0 | return "authority cert fetch"; |
115 | 0 | case DIR_PURPOSE_FETCH_STATUS_VOTE: |
116 | 0 | return "status vote fetch"; |
117 | 0 | case DIR_PURPOSE_FETCH_DETACHED_SIGNATURES: |
118 | 0 | return "consensus signature fetch"; |
119 | 0 | case DIR_PURPOSE_FETCH_HSDESC: |
120 | 0 | return "hidden-service descriptor fetch"; |
121 | 0 | case DIR_PURPOSE_UPLOAD_HSDESC: |
122 | 0 | return "hidden-service descriptor upload"; |
123 | 0 | case DIR_PURPOSE_FETCH_MICRODESC: |
124 | 0 | return "microdescriptor fetch"; |
125 | 0 | } |
126 | | |
127 | 0 | log_warn(LD_BUG, "Called with unknown purpose %d", purpose); |
128 | 0 | return "(unknown)"; |
129 | 0 | } |
130 | | |
131 | | /** Return the requisite directory information types. */ |
132 | | STATIC dirinfo_type_t |
133 | | dir_fetch_type(int dir_purpose, int router_purpose, const char *resource) |
134 | 0 | { |
135 | 0 | dirinfo_type_t type; |
136 | 0 | switch (dir_purpose) { |
137 | 0 | case DIR_PURPOSE_FETCH_EXTRAINFO: |
138 | 0 | type = EXTRAINFO_DIRINFO; |
139 | 0 | if (router_purpose == ROUTER_PURPOSE_BRIDGE) |
140 | 0 | type |= BRIDGE_DIRINFO; |
141 | 0 | else |
142 | 0 | type |= V3_DIRINFO; |
143 | 0 | break; |
144 | 0 | case DIR_PURPOSE_FETCH_SERVERDESC: |
145 | 0 | if (router_purpose == ROUTER_PURPOSE_BRIDGE) |
146 | 0 | type = BRIDGE_DIRINFO; |
147 | 0 | else |
148 | 0 | type = V3_DIRINFO; |
149 | 0 | break; |
150 | 0 | case DIR_PURPOSE_FETCH_STATUS_VOTE: |
151 | 0 | case DIR_PURPOSE_FETCH_DETACHED_SIGNATURES: |
152 | 0 | case DIR_PURPOSE_FETCH_CERTIFICATE: |
153 | 0 | type = V3_DIRINFO; |
154 | 0 | break; |
155 | 0 | case DIR_PURPOSE_FETCH_CONSENSUS: |
156 | 0 | type = V3_DIRINFO; |
157 | 0 | if (resource && !strcmp(resource, "microdesc")) |
158 | 0 | type |= MICRODESC_DIRINFO; |
159 | 0 | break; |
160 | 0 | case DIR_PURPOSE_FETCH_MICRODESC: |
161 | 0 | type = MICRODESC_DIRINFO; |
162 | 0 | break; |
163 | 0 | default: |
164 | 0 | log_warn(LD_BUG, "Unexpected purpose %d", (int)dir_purpose); |
165 | 0 | type = NO_DIRINFO; |
166 | 0 | break; |
167 | 0 | } |
168 | 0 | return type; |
169 | 0 | } |
170 | | |
171 | | /** Return true iff <b>identity_digest</b> is the digest of a router which |
172 | | * says that it caches extrainfos. (If <b>is_authority</b> we always |
173 | | * believe that to be true.) */ |
174 | | int |
175 | | router_supports_extrainfo(const char *identity_digest, int is_authority) |
176 | 0 | { |
177 | 0 | const node_t *node = node_get_by_id(identity_digest); |
178 | |
|
179 | 0 | if (node && node->ri) { |
180 | 0 | if (node->ri->caches_extra_info) |
181 | 0 | return 1; |
182 | 0 | } |
183 | 0 | if (is_authority) { |
184 | 0 | return 1; |
185 | 0 | } |
186 | 0 | return 0; |
187 | 0 | } |
188 | | |
189 | | /** Return true iff any trusted directory authority has accepted our |
190 | | * server descriptor. |
191 | | * |
192 | | * We consider any authority sufficient because waiting for all of |
193 | | * them means it never happens while any authority is down; we don't |
194 | | * go for something more complex in the middle (like \>1/3 or \>1/2 or |
195 | | * \>=1/2) because that doesn't seem necessary yet. |
196 | | */ |
197 | | int |
198 | | directories_have_accepted_server_descriptor(void) |
199 | 0 | { |
200 | 0 | const smartlist_t *servers = router_get_trusted_dir_servers(); |
201 | 0 | const or_options_t *options = get_options(); |
202 | 0 | SMARTLIST_FOREACH(servers, dir_server_t *, d, { |
203 | 0 | if ((d->type & options->PublishServerDescriptor_) && |
204 | 0 | d->has_accepted_serverdesc) { |
205 | 0 | return 1; |
206 | 0 | } |
207 | 0 | }); |
208 | 0 | return 0; |
209 | 0 | } |
210 | | |
211 | | /** Start a connection to every suitable directory authority, using |
212 | | * connection purpose <b>dir_purpose</b> and uploading <b>payload</b> |
213 | | * (of length <b>payload_len</b>). The dir_purpose should be one of |
214 | | * 'DIR_PURPOSE_UPLOAD_{DIR|VOTE|SIGNATURES}'. |
215 | | * |
216 | | * <b>router_purpose</b> describes the type of descriptor we're |
217 | | * publishing, if we're publishing a descriptor -- e.g. general or bridge. |
218 | | * |
219 | | * <b>type</b> specifies what sort of dir authorities (V3, |
220 | | * BRIDGE, etc) we should upload to. |
221 | | * |
222 | | * If <b>extrainfo_len</b> is nonzero, the first <b>payload_len</b> bytes of |
223 | | * <b>payload</b> hold a router descriptor, and the next <b>extrainfo_len</b> |
224 | | * bytes of <b>payload</b> hold an extra-info document. Upload the descriptor |
225 | | * to all authorities, and the extra-info document to all authorities that |
226 | | * support it. |
227 | | */ |
228 | | void |
229 | | directory_post_to_dirservers(uint8_t dir_purpose, uint8_t router_purpose, |
230 | | dirinfo_type_t type, |
231 | | const char *payload, |
232 | | size_t payload_len, size_t extrainfo_len) |
233 | 0 | { |
234 | 0 | const or_options_t *options = get_options(); |
235 | 0 | dir_indirection_t indirection; |
236 | 0 | const smartlist_t *dirservers = router_get_trusted_dir_servers(); |
237 | 0 | int found = 0; |
238 | 0 | const int exclude_self = (dir_purpose == DIR_PURPOSE_UPLOAD_VOTE || |
239 | 0 | dir_purpose == DIR_PURPOSE_UPLOAD_SIGNATURES); |
240 | 0 | tor_assert(dirservers); |
241 | | /* This tries dirservers which we believe to be down, but ultimately, that's |
242 | | * harmless, and we may as well err on the side of getting things uploaded. |
243 | | */ |
244 | 0 | SMARTLIST_FOREACH_BEGIN(dirservers, dir_server_t *, ds) { |
245 | 0 | const routerstatus_t *rs = router_get_consensus_status_by_id(ds->digest); |
246 | 0 | if (!rs) { |
247 | | /* prefer to use the address in the consensus, but fall back to |
248 | | * the hard-coded trusted_dir_server address if we don't have a |
249 | | * consensus or this digest isn't in our consensus. */ |
250 | 0 | rs = &ds->fake_status; |
251 | 0 | } |
252 | |
|
253 | 0 | size_t upload_len = payload_len; |
254 | |
|
255 | 0 | if ((type & ds->type) == 0) |
256 | 0 | continue; |
257 | | |
258 | 0 | if (exclude_self && router_digest_is_me(ds->digest)) { |
259 | | /* we don't upload to ourselves, but there's now at least |
260 | | * one authority of this type that has what we wanted to upload. */ |
261 | 0 | found = 1; |
262 | 0 | continue; |
263 | 0 | } |
264 | | |
265 | 0 | if (options->StrictNodes && |
266 | 0 | routerset_contains_routerstatus(options->ExcludeNodes, rs, -1)) { |
267 | 0 | log_warn(LD_DIR, "Wanted to contact authority '%s' for %s, but " |
268 | 0 | "it's in our ExcludedNodes list and StrictNodes is set. " |
269 | 0 | "Skipping.", |
270 | 0 | ds->nickname, |
271 | 0 | dir_conn_purpose_to_string(dir_purpose)); |
272 | 0 | continue; |
273 | 0 | } |
274 | | |
275 | 0 | found = 1; /* at least one authority of this type was listed */ |
276 | 0 | if (dir_purpose == DIR_PURPOSE_UPLOAD_DIR) |
277 | 0 | ds->has_accepted_serverdesc = 0; |
278 | |
|
279 | 0 | if (extrainfo_len && router_supports_extrainfo(ds->digest, 1)) { |
280 | 0 | upload_len += extrainfo_len; |
281 | 0 | log_info(LD_DIR, "Uploading an extrainfo too (length %d)", |
282 | 0 | (int) extrainfo_len); |
283 | 0 | } |
284 | 0 | if (purpose_needs_anonymity(dir_purpose, router_purpose, NULL)) { |
285 | 0 | indirection = DIRIND_ANONYMOUS; |
286 | 0 | } else if (!reachable_addr_allows_rs(rs, FIREWALL_DIR_CONNECTION, 0)) { |
287 | 0 | if (reachable_addr_allows_rs(rs, FIREWALL_OR_CONNECTION, 0)) |
288 | 0 | indirection = DIRIND_ONEHOP; |
289 | 0 | else |
290 | 0 | indirection = DIRIND_ANONYMOUS; |
291 | 0 | } else { |
292 | 0 | indirection = DIRIND_DIRECT_CONN; |
293 | 0 | } |
294 | |
|
295 | 0 | directory_request_t *req = directory_request_new(dir_purpose); |
296 | 0 | directory_request_set_routerstatus(req, rs); |
297 | 0 | directory_request_set_router_purpose(req, router_purpose); |
298 | 0 | directory_request_set_indirection(req, indirection); |
299 | 0 | directory_request_set_payload(req, payload, upload_len); |
300 | 0 | directory_initiate_request(req); |
301 | 0 | directory_request_free(req); |
302 | 0 | } SMARTLIST_FOREACH_END(ds); |
303 | 0 | if (!found) { |
304 | 0 | char *s = authdir_type_to_string(type); |
305 | 0 | log_warn(LD_DIR, "Publishing server descriptor to directory authorities " |
306 | 0 | "of type '%s', but no authorities of that type listed!", s); |
307 | 0 | tor_free(s); |
308 | 0 | } |
309 | 0 | } |
310 | | |
311 | | /** Return true iff, according to the values in <b>options</b>, we should be |
312 | | * using directory guards for direct downloads of directory information. */ |
313 | | STATIC int |
314 | | should_use_directory_guards(const or_options_t *options) |
315 | 0 | { |
316 | | /* Public (non-bridge) servers never use directory guards. */ |
317 | 0 | if (public_server_mode(options)) |
318 | 0 | return 0; |
319 | | /* If guards are disabled, we can't use directory guards. |
320 | | */ |
321 | 0 | if (!options->UseEntryGuards) |
322 | 0 | return 0; |
323 | | /* If we're configured to fetch directory info aggressively or of a |
324 | | * nonstandard type, don't use directory guards. */ |
325 | 0 | if (options->DownloadExtraInfo || options->FetchDirInfoEarly || |
326 | 0 | options->FetchDirInfoExtraEarly || options->FetchUselessDescriptors) |
327 | 0 | return 0; |
328 | 0 | return 1; |
329 | 0 | } |
330 | | |
331 | | /** Pick an unconstrained directory server from among our guards, the latest |
332 | | * networkstatus, or the fallback dirservers, for use in downloading |
333 | | * information of type <b>type</b>, and return its routerstatus. */ |
334 | | static const routerstatus_t * |
335 | | directory_pick_generic_dirserver(dirinfo_type_t type, int pds_flags, |
336 | | uint8_t dir_purpose, |
337 | | circuit_guard_state_t **guard_state_out) |
338 | 0 | { |
339 | 0 | const routerstatus_t *rs = NULL; |
340 | 0 | const or_options_t *options = get_options(); |
341 | |
|
342 | 0 | if (options->UseBridges) |
343 | 0 | log_warn(LD_BUG, "Called when we have UseBridges set."); |
344 | |
|
345 | 0 | if (should_use_directory_guards(options)) { |
346 | 0 | const node_t *node = guards_choose_dirguard(dir_purpose, guard_state_out); |
347 | 0 | if (node) |
348 | 0 | rs = node->rs; |
349 | 0 | } else { |
350 | | /* anybody with a non-zero dirport will do */ |
351 | 0 | rs = router_pick_directory_server(type, pds_flags); |
352 | 0 | } |
353 | 0 | if (!rs) { |
354 | 0 | log_info(LD_DIR, "No router found for %s; falling back to " |
355 | 0 | "dirserver list.", dir_conn_purpose_to_string(dir_purpose)); |
356 | 0 | rs = router_pick_fallback_dirserver(type, pds_flags); |
357 | 0 | } |
358 | |
|
359 | 0 | return rs; |
360 | 0 | } |
361 | | |
362 | | /** |
363 | | * Set the extra fields in <b>req</b> that are used when requesting a |
364 | | * consensus of type <b>resource</b>. |
365 | | * |
366 | | * Right now, these fields are if-modified-since and x-or-diff-from-consensus. |
367 | | */ |
368 | | static void |
369 | | dir_consensus_request_set_additional_headers(directory_request_t *req, |
370 | | const char *resource) |
371 | 0 | { |
372 | 0 | time_t if_modified_since = 0; |
373 | 0 | uint8_t or_diff_from[DIGEST256_LEN]; |
374 | 0 | int or_diff_from_is_set = 0; |
375 | | |
376 | | /* DEFAULT_IF_MODIFIED_SINCE_DELAY is 1/20 of the default consensus |
377 | | * period of 1 hour. |
378 | | */ |
379 | 0 | const int DEFAULT_IF_MODIFIED_SINCE_DELAY = 180; |
380 | 0 | const int32_t DEFAULT_TRY_DIFF_FOR_CONSENSUS_NEWER = 72; |
381 | 0 | const int32_t MIN_TRY_DIFF_FOR_CONSENSUS_NEWER = 0; |
382 | 0 | const int32_t MAX_TRY_DIFF_FOR_CONSENSUS_NEWER = 8192; |
383 | 0 | const char TRY_DIFF_FOR_CONSENSUS_NEWER_NAME[] = |
384 | 0 | "try-diff-for-consensus-newer-than"; |
385 | |
|
386 | 0 | int flav = FLAV_NS; |
387 | 0 | if (resource) |
388 | 0 | flav = networkstatus_parse_flavor_name(resource); |
389 | |
|
390 | 0 | int32_t max_age_for_diff = 3600 * |
391 | 0 | networkstatus_get_param(NULL, |
392 | 0 | TRY_DIFF_FOR_CONSENSUS_NEWER_NAME, |
393 | 0 | DEFAULT_TRY_DIFF_FOR_CONSENSUS_NEWER, |
394 | 0 | MIN_TRY_DIFF_FOR_CONSENSUS_NEWER, |
395 | 0 | MAX_TRY_DIFF_FOR_CONSENSUS_NEWER); |
396 | |
|
397 | 0 | if (flav != -1) { |
398 | | /* IF we have a parsed consensus of this type, we can do an |
399 | | * if-modified-time based on it. */ |
400 | 0 | networkstatus_t *v; |
401 | 0 | v = networkstatus_get_latest_consensus_by_flavor(flav); |
402 | 0 | if (v) { |
403 | | /* In networks with particularly short V3AuthVotingIntervals, |
404 | | * ask for the consensus if it's been modified since half the |
405 | | * V3AuthVotingInterval of the most recent consensus. */ |
406 | 0 | time_t ims_delay = DEFAULT_IF_MODIFIED_SINCE_DELAY; |
407 | 0 | if (v->fresh_until > v->valid_after |
408 | 0 | && ims_delay > (v->fresh_until - v->valid_after)/2) { |
409 | 0 | ims_delay = (v->fresh_until - v->valid_after)/2; |
410 | 0 | } |
411 | 0 | if_modified_since = v->valid_after + ims_delay; |
412 | 0 | if (v->valid_after >= approx_time() - max_age_for_diff) { |
413 | 0 | memcpy(or_diff_from, v->digest_sha3_as_signed, DIGEST256_LEN); |
414 | 0 | or_diff_from_is_set = 1; |
415 | 0 | } |
416 | 0 | } |
417 | 0 | } else { |
418 | | /* Otherwise it might be a consensus we don't parse, but which we |
419 | | * do cache. Look at the cached copy, perhaps. */ |
420 | 0 | cached_dir_t *cd = dirserv_get_consensus(resource); |
421 | | /* We have no method of determining the voting interval from an |
422 | | * unparsed consensus, so we use the default. */ |
423 | 0 | if (cd) { |
424 | 0 | if_modified_since = cd->published + DEFAULT_IF_MODIFIED_SINCE_DELAY; |
425 | 0 | if (cd->published >= approx_time() - max_age_for_diff) { |
426 | 0 | memcpy(or_diff_from, cd->digest_sha3_as_signed, DIGEST256_LEN); |
427 | 0 | or_diff_from_is_set = 1; |
428 | 0 | } |
429 | 0 | } |
430 | 0 | } |
431 | |
|
432 | 0 | if (if_modified_since > 0) |
433 | 0 | directory_request_set_if_modified_since(req, if_modified_since); |
434 | 0 | if (or_diff_from_is_set) { |
435 | 0 | char hex[HEX_DIGEST256_LEN + 1]; |
436 | 0 | base16_encode(hex, sizeof(hex), |
437 | 0 | (const char*)or_diff_from, sizeof(or_diff_from)); |
438 | 0 | directory_request_add_header(req, X_OR_DIFF_FROM_CONSENSUS_HEADER, hex); |
439 | 0 | } |
440 | 0 | } |
441 | | /** Start a connection to a random running directory server, using |
442 | | * connection purpose <b>dir_purpose</b>, intending to fetch descriptors |
443 | | * of purpose <b>router_purpose</b>, and requesting <b>resource</b>. |
444 | | * Use <b>pds_flags</b> as arguments to router_pick_directory_server() |
445 | | * or router_pick_trusteddirserver(). |
446 | | */ |
447 | | MOCK_IMPL(void, |
448 | | directory_get_from_dirserver,( |
449 | | uint8_t dir_purpose, |
450 | | uint8_t router_purpose, |
451 | | const char *resource, |
452 | | int pds_flags, |
453 | | download_want_authority_t want_authority)) |
454 | 0 | { |
455 | 0 | const routerstatus_t *rs = NULL; |
456 | 0 | const or_options_t *options = get_options(); |
457 | 0 | int prefer_authority = (dirclient_fetches_from_authorities(options) |
458 | 0 | || want_authority == DL_WANT_AUTHORITY); |
459 | 0 | int require_authority = 0; |
460 | 0 | int get_via_tor = purpose_needs_anonymity(dir_purpose, router_purpose, |
461 | 0 | resource); |
462 | 0 | dirinfo_type_t type = dir_fetch_type(dir_purpose, router_purpose, resource); |
463 | |
|
464 | 0 | if (type == NO_DIRINFO) |
465 | 0 | return; |
466 | | |
467 | 0 | if (!options->FetchServerDescriptors) |
468 | 0 | return; |
469 | | |
470 | 0 | circuit_guard_state_t *guard_state = NULL; |
471 | 0 | if (!get_via_tor) { |
472 | 0 | if (options->UseBridges && !(type & BRIDGE_DIRINFO)) { |
473 | | /* We want to ask a running bridge for which we have a descriptor. |
474 | | * |
475 | | * When we ask choose_random_entry() for a bridge, we specify what |
476 | | * sort of dir fetch we'll be doing, so it won't return a bridge |
477 | | * that can't answer our question. |
478 | | */ |
479 | 0 | const node_t *node = guards_choose_dirguard(dir_purpose, &guard_state); |
480 | 0 | if (node && node->ri) { |
481 | | /* every bridge has a routerinfo. */ |
482 | 0 | routerinfo_t *ri = node->ri; |
483 | | /* clients always make OR connections to bridges */ |
484 | 0 | tor_addr_port_t or_ap; |
485 | 0 | directory_request_t *req = directory_request_new(dir_purpose); |
486 | | /* we are willing to use a non-preferred address if we need to */ |
487 | 0 | reachable_addr_choose_from_node(node, FIREWALL_OR_CONNECTION, 0, |
488 | 0 | &or_ap); |
489 | 0 | directory_request_set_or_addr_port(req, &or_ap); |
490 | 0 | directory_request_set_directory_id_digest(req, |
491 | 0 | ri->cache_info.identity_digest); |
492 | 0 | directory_request_set_router_purpose(req, router_purpose); |
493 | 0 | directory_request_set_resource(req, resource); |
494 | 0 | if (dir_purpose == DIR_PURPOSE_FETCH_CONSENSUS) |
495 | 0 | dir_consensus_request_set_additional_headers(req, resource); |
496 | 0 | directory_request_set_guard_state(req, guard_state); |
497 | 0 | directory_initiate_request(req); |
498 | 0 | directory_request_free(req); |
499 | 0 | } else { |
500 | 0 | if (guard_state) { |
501 | 0 | entry_guard_cancel(&guard_state); |
502 | 0 | } |
503 | 0 | log_notice(LD_DIR, "Ignoring directory request, since no bridge " |
504 | 0 | "nodes are available yet."); |
505 | 0 | } |
506 | |
|
507 | 0 | return; |
508 | 0 | } else { |
509 | 0 | if (prefer_authority || (type & BRIDGE_DIRINFO)) { |
510 | | /* only ask authdirservers, and don't ask myself */ |
511 | 0 | rs = router_pick_trusteddirserver(type, pds_flags); |
512 | 0 | if (rs == NULL && (pds_flags & (PDS_NO_EXISTING_SERVERDESC_FETCH| |
513 | 0 | PDS_NO_EXISTING_MICRODESC_FETCH))) { |
514 | | /* We don't want to fetch from any authorities that we're currently |
515 | | * fetching server descriptors from, and we got no match. Did we |
516 | | * get no match because all the authorities have connections |
517 | | * fetching server descriptors (in which case we should just |
518 | | * return,) or because all the authorities are down or on fire or |
519 | | * unreachable or something (in which case we should go on with |
520 | | * our fallback code)? */ |
521 | 0 | pds_flags &= ~(PDS_NO_EXISTING_SERVERDESC_FETCH| |
522 | 0 | PDS_NO_EXISTING_MICRODESC_FETCH); |
523 | 0 | rs = router_pick_trusteddirserver(type, pds_flags); |
524 | 0 | if (rs) { |
525 | 0 | log_debug(LD_DIR, "Deferring serverdesc fetch: all authorities " |
526 | 0 | "are in use."); |
527 | 0 | return; |
528 | 0 | } |
529 | 0 | } |
530 | 0 | if (rs == NULL && require_authority) { |
531 | 0 | log_info(LD_DIR, "No authorities were available for %s: will try " |
532 | 0 | "later.", dir_conn_purpose_to_string(dir_purpose)); |
533 | 0 | return; |
534 | 0 | } |
535 | 0 | } |
536 | 0 | if (!rs && !(type & BRIDGE_DIRINFO)) { |
537 | 0 | rs = directory_pick_generic_dirserver(type, pds_flags, |
538 | 0 | dir_purpose, |
539 | 0 | &guard_state); |
540 | 0 | if (!rs) |
541 | 0 | get_via_tor = 1; /* last resort: try routing it via Tor */ |
542 | 0 | } |
543 | 0 | } |
544 | 0 | } |
545 | | |
546 | 0 | if (get_via_tor) { |
547 | | /* Never use fascistfirewall; we're going via Tor. */ |
548 | 0 | pds_flags |= PDS_IGNORE_FASCISTFIREWALL; |
549 | 0 | rs = router_pick_directory_server(type, pds_flags); |
550 | 0 | } |
551 | | |
552 | | /* If we have any hope of building an indirect conn, we know some router |
553 | | * descriptors. If (rs==NULL), we can't build circuits anyway, so |
554 | | * there's no point in falling back to the authorities in this case. */ |
555 | 0 | if (rs) { |
556 | 0 | const dir_indirection_t indirection = |
557 | 0 | get_via_tor ? DIRIND_ANONYMOUS : DIRIND_ONEHOP; |
558 | 0 | directory_request_t *req = directory_request_new(dir_purpose); |
559 | 0 | directory_request_set_routerstatus(req, rs); |
560 | 0 | directory_request_set_router_purpose(req, router_purpose); |
561 | 0 | directory_request_set_indirection(req, indirection); |
562 | 0 | directory_request_set_resource(req, resource); |
563 | 0 | if (dir_purpose == DIR_PURPOSE_FETCH_CONSENSUS) |
564 | 0 | dir_consensus_request_set_additional_headers(req, resource); |
565 | 0 | if (guard_state) |
566 | 0 | directory_request_set_guard_state(req, guard_state); |
567 | 0 | directory_initiate_request(req); |
568 | 0 | directory_request_free(req); |
569 | 0 | } else { |
570 | 0 | log_notice(LD_DIR, |
571 | 0 | "While fetching directory info, " |
572 | 0 | "no running dirservers known. Will try again later. " |
573 | 0 | "(purpose %d)", dir_purpose); |
574 | 0 | if (!purpose_needs_anonymity(dir_purpose, router_purpose, resource)) { |
575 | | /* remember we tried them all and failed. */ |
576 | 0 | directory_all_unreachable(time(NULL)); |
577 | 0 | } |
578 | 0 | } |
579 | 0 | } |
580 | | |
581 | | /** As directory_get_from_dirserver, but initiates a request to <i>every</i> |
582 | | * directory authority other than ourself. Only for use by authorities when |
583 | | * searching for missing information while voting. */ |
584 | | void |
585 | | directory_get_from_all_authorities(uint8_t dir_purpose, |
586 | | uint8_t router_purpose, |
587 | | const char *resource) |
588 | 0 | { |
589 | 0 | tor_assert(dir_purpose == DIR_PURPOSE_FETCH_STATUS_VOTE || |
590 | 0 | dir_purpose == DIR_PURPOSE_FETCH_DETACHED_SIGNATURES); |
591 | |
|
592 | 0 | SMARTLIST_FOREACH_BEGIN(router_get_trusted_dir_servers(), |
593 | 0 | dir_server_t *, ds) { |
594 | 0 | if (router_digest_is_me(ds->digest)) |
595 | 0 | continue; |
596 | 0 | if (!(ds->type & V3_DIRINFO)) |
597 | 0 | continue; |
598 | 0 | const routerstatus_t *rs = router_get_consensus_status_by_id(ds->digest); |
599 | 0 | if (!rs) { |
600 | | /* prefer to use the address in the consensus, but fall back to |
601 | | * the hard-coded trusted_dir_server address if we don't have a |
602 | | * consensus or this digest isn't in our consensus. */ |
603 | 0 | rs = &ds->fake_status; |
604 | 0 | } |
605 | 0 | directory_request_t *req = directory_request_new(dir_purpose); |
606 | 0 | directory_request_set_routerstatus(req, rs); |
607 | 0 | directory_request_set_router_purpose(req, router_purpose); |
608 | 0 | directory_request_set_resource(req, resource); |
609 | 0 | directory_initiate_request(req); |
610 | 0 | directory_request_free(req); |
611 | 0 | } SMARTLIST_FOREACH_END(ds); |
612 | 0 | } |
613 | | |
614 | | /** Return true iff <b>ind</b> requires a multihop circuit. */ |
615 | | static int |
616 | | dirind_is_anon(dir_indirection_t ind) |
617 | 0 | { |
618 | 0 | return ind == DIRIND_ANON_DIRPORT || ind == DIRIND_ANONYMOUS; |
619 | 0 | } |
620 | | |
621 | | /* Choose reachable OR and Dir addresses and ports from status, copying them |
622 | | * into use_or_ap and use_dir_ap. If indirection is anonymous, then we're |
623 | | * connecting via another relay, so choose the primary IPv4 address and ports. |
624 | | * |
625 | | * status should have at least one reachable address, if we can't choose a |
626 | | * reachable address, warn and return -1. Otherwise, return 0. |
627 | | */ |
628 | | static int |
629 | | directory_choose_address_routerstatus(const routerstatus_t *status, |
630 | | dir_indirection_t indirection, |
631 | | tor_addr_port_t *use_or_ap, |
632 | | tor_addr_port_t *use_dir_ap) |
633 | 0 | { |
634 | 0 | tor_assert(status != NULL); |
635 | 0 | tor_assert(use_or_ap != NULL); |
636 | 0 | tor_assert(use_dir_ap != NULL); |
637 | |
|
638 | 0 | const or_options_t *options = get_options(); |
639 | 0 | int have_or = 0, have_dir = 0; |
640 | | |
641 | | /* We expect status to have at least one reachable address if we're |
642 | | * connecting to it directly. |
643 | | * |
644 | | * Therefore, we can simply use the other address if the one we want isn't |
645 | | * allowed by the firewall. |
646 | | * |
647 | | * (When Tor uploads and downloads a hidden service descriptor, it uses |
648 | | * DIRIND_ANONYMOUS. Even Single Onion Servers (NYI) use DIRIND_ANONYMOUS, |
649 | | * to avoid HSDirs denying service by rejecting descriptors.) |
650 | | */ |
651 | | |
652 | | /* Initialise the OR / Dir addresses */ |
653 | 0 | tor_addr_make_null(&use_or_ap->addr, AF_UNSPEC); |
654 | 0 | use_or_ap->port = 0; |
655 | 0 | tor_addr_make_null(&use_dir_ap->addr, AF_UNSPEC); |
656 | 0 | use_dir_ap->port = 0; |
657 | | |
658 | | /* ORPort connections */ |
659 | 0 | if (indirection == DIRIND_ANONYMOUS) { |
660 | 0 | if (!tor_addr_is_null(&status->ipv4_addr)) { |
661 | | /* Since we're going to build a 3-hop circuit and ask the 2nd relay |
662 | | * to extend to this address, always use the primary (IPv4) OR address */ |
663 | 0 | tor_addr_copy(&use_or_ap->addr, &status->ipv4_addr); |
664 | 0 | use_or_ap->port = status->ipv4_orport; |
665 | 0 | have_or = 1; |
666 | 0 | } |
667 | 0 | } else if (indirection == DIRIND_ONEHOP) { |
668 | | /* We use an IPv6 address if we have one and we prefer it. |
669 | | * Use the preferred address and port if they are reachable, otherwise, |
670 | | * use the alternate address and port (if any). |
671 | | */ |
672 | 0 | reachable_addr_choose_from_rs(status, FIREWALL_OR_CONNECTION, 0, |
673 | 0 | use_or_ap); |
674 | 0 | have_or = tor_addr_port_is_valid_ap(use_or_ap, 0); |
675 | 0 | } |
676 | | |
677 | | /* DirPort connections |
678 | | * DIRIND_ONEHOP uses ORPort, but may fall back to the DirPort on relays */ |
679 | 0 | if (indirection == DIRIND_DIRECT_CONN || |
680 | 0 | indirection == DIRIND_ANON_DIRPORT || |
681 | 0 | (indirection == DIRIND_ONEHOP |
682 | 0 | && !dirclient_must_use_begindir(options))) { |
683 | 0 | reachable_addr_choose_from_rs(status, FIREWALL_DIR_CONNECTION, 0, |
684 | 0 | use_dir_ap); |
685 | 0 | have_dir = tor_addr_port_is_valid_ap(use_dir_ap, 0); |
686 | 0 | } |
687 | | |
688 | | /* We rejected all addresses in the relay's status. This means we can't |
689 | | * connect to it. */ |
690 | 0 | if (!have_or && !have_dir) { |
691 | 0 | char *ipv6_str = tor_addr_to_str_dup(&status->ipv6_addr); |
692 | 0 | log_info(LD_BUG, "Rejected all OR and Dir addresses from %s when " |
693 | 0 | "launching an outgoing directory connection to: IPv4 %s OR %d " |
694 | 0 | "Dir %d IPv6 %s OR %d Dir %d", routerstatus_describe(status), |
695 | 0 | fmt_addr(&status->ipv4_addr), status->ipv4_orport, |
696 | 0 | status->ipv4_dirport, ipv6_str, status->ipv6_orport, |
697 | 0 | status->ipv4_dirport); |
698 | 0 | tor_free(ipv6_str); |
699 | 0 | log_backtrace_once(LOG_INFO, LD_BUG, "Addresses came from"); |
700 | 0 | return -1; |
701 | 0 | } |
702 | | |
703 | 0 | return 0; |
704 | 0 | } |
705 | | |
706 | | /** Called when we are unable to complete the client's request to a directory |
707 | | * server due to a network error: Mark the router as down and try again if |
708 | | * possible. |
709 | | */ |
710 | | void |
711 | | connection_dir_client_request_failed(dir_connection_t *conn) |
712 | 0 | { |
713 | 0 | if (conn->guard_state) { |
714 | | /* We haven't seen a success on this guard state, so consider it to have |
715 | | * failed. */ |
716 | 0 | entry_guard_failed(&conn->guard_state); |
717 | 0 | } |
718 | 0 | if (!entry_list_is_constrained(get_options())) |
719 | | /* We must not set a directory to non-running for HS purposes else we end |
720 | | * up flagging nodes from the hashring has unusable. It doesn't have direct |
721 | | * effect on the HS subsystem because the nodes are selected regardless of |
722 | | * their status but still, we shouldn't flag them as non running. |
723 | | * |
724 | | * One example where this can go bad is if a tor instance gets added a lot |
725 | | * of ephemeral services and with a network with problem then many nodes in |
726 | | * the consenus ends up unusable. |
727 | | * |
728 | | * Furthermore, a service does close any pending directory connections |
729 | | * before uploading a descriptor and thus we can end up here in a natural |
730 | | * way since closing a pending directory connection leads to this code |
731 | | * path. */ |
732 | 0 | if (!DIR_PURPOSE_IS_HS(TO_CONN(conn)->purpose)) { |
733 | 0 | router_set_status(conn->identity_digest, 0); |
734 | 0 | } |
735 | 0 | if (conn->base_.purpose == DIR_PURPOSE_FETCH_SERVERDESC || |
736 | 0 | conn->base_.purpose == DIR_PURPOSE_FETCH_EXTRAINFO) { |
737 | 0 | log_info(LD_DIR, "Giving up on serverdesc/extrainfo fetch from " |
738 | 0 | "directory server at %s; retrying", |
739 | 0 | connection_describe_peer(TO_CONN(conn))); |
740 | 0 | if (conn->router_purpose == ROUTER_PURPOSE_BRIDGE) |
741 | 0 | connection_dir_bridge_routerdesc_failed(conn); |
742 | 0 | connection_dir_download_routerdesc_failed(conn); |
743 | 0 | } else if (conn->base_.purpose == DIR_PURPOSE_FETCH_CONSENSUS) { |
744 | 0 | if (conn->requested_resource) |
745 | 0 | networkstatus_consensus_download_failed(0, conn->requested_resource); |
746 | 0 | } else if (conn->base_.purpose == DIR_PURPOSE_FETCH_CERTIFICATE) { |
747 | 0 | log_info(LD_DIR, "Giving up on certificate fetch from directory server " |
748 | 0 | "at %s; retrying", |
749 | 0 | connection_describe_peer(TO_CONN(conn))); |
750 | 0 | connection_dir_download_cert_failed(conn, 0); |
751 | 0 | } else if (conn->base_.purpose == DIR_PURPOSE_FETCH_DETACHED_SIGNATURES) { |
752 | 0 | log_info(LD_DIR, "Giving up downloading detached signatures from %s", |
753 | 0 | connection_describe_peer(TO_CONN(conn))); |
754 | 0 | } else if (conn->base_.purpose == DIR_PURPOSE_FETCH_STATUS_VOTE) { |
755 | 0 | log_info(LD_DIR, "Giving up downloading votes from %s", |
756 | 0 | connection_describe_peer(TO_CONN(conn))); |
757 | 0 | } else if (conn->base_.purpose == DIR_PURPOSE_FETCH_MICRODESC) { |
758 | 0 | log_info(LD_DIR, "Giving up on downloading microdescriptors from " |
759 | 0 | "directory server at %s; will retry", |
760 | 0 | connection_describe_peer(TO_CONN(conn))); |
761 | 0 | connection_dir_download_routerdesc_failed(conn); |
762 | 0 | } else if (conn->base_.purpose == DIR_PURPOSE_UPLOAD_VOTE || |
763 | 0 | conn->base_.purpose == DIR_PURPOSE_UPLOAD_SIGNATURES) { |
764 | 0 | log_warn(LD_DIR, "Failed to post %s to %s.", |
765 | 0 | dir_conn_purpose_to_string(conn->base_.purpose), |
766 | 0 | connection_describe_peer(TO_CONN(conn))); |
767 | 0 | } |
768 | 0 | } |
769 | | |
770 | | /** Helper: Attempt to fetch directly the descriptors of each bridge |
771 | | * listed in <b>failed</b>. |
772 | | */ |
773 | | static void |
774 | | connection_dir_retry_bridges(smartlist_t *descs) |
775 | 0 | { |
776 | 0 | char digest[DIGEST_LEN]; |
777 | 0 | SMARTLIST_FOREACH(descs, const char *, cp, |
778 | 0 | { |
779 | 0 | if (base16_decode(digest, DIGEST_LEN, cp, strlen(cp)) != DIGEST_LEN) { |
780 | 0 | log_warn(LD_BUG, "Malformed fingerprint in list: %s", |
781 | 0 | escaped(cp)); |
782 | 0 | continue; |
783 | 0 | } |
784 | 0 | retry_bridge_descriptor_fetch_directly(digest); |
785 | 0 | }); |
786 | 0 | } |
787 | | |
788 | | /** Called when an attempt to download one or more router descriptors |
789 | | * or extra-info documents on connection <b>conn</b> failed. |
790 | | */ |
791 | | static void |
792 | | connection_dir_download_routerdesc_failed(dir_connection_t *conn) |
793 | 0 | { |
794 | | /* No need to increment the failure count for routerdescs, since |
795 | | * it's not their fault. */ |
796 | | |
797 | | /* No need to relaunch descriptor downloads here: we already do it |
798 | | * every 10 or 60 seconds (FOO_DESCRIPTOR_RETRY_INTERVAL) in main.c. */ |
799 | 0 | tor_assert(conn->base_.purpose == DIR_PURPOSE_FETCH_SERVERDESC || |
800 | 0 | conn->base_.purpose == DIR_PURPOSE_FETCH_EXTRAINFO || |
801 | 0 | conn->base_.purpose == DIR_PURPOSE_FETCH_MICRODESC); |
802 | |
|
803 | 0 | (void) conn; |
804 | 0 | } |
805 | | |
806 | | /** Called when an attempt to download a bridge's routerdesc from |
807 | | * one of the authorities failed due to a network error. If |
808 | | * possible attempt to download descriptors from the bridge directly. |
809 | | */ |
810 | | static void |
811 | | connection_dir_bridge_routerdesc_failed(dir_connection_t *conn) |
812 | 0 | { |
813 | 0 | smartlist_t *which = NULL; |
814 | | |
815 | | /* Requests for bridge descriptors are in the form 'fp/', so ignore |
816 | | anything else. */ |
817 | 0 | if (!conn->requested_resource || strcmpstart(conn->requested_resource,"fp/")) |
818 | 0 | return; |
819 | | |
820 | 0 | which = smartlist_new(); |
821 | 0 | dir_split_resource_into_fingerprints(conn->requested_resource |
822 | 0 | + strlen("fp/"), |
823 | 0 | which, NULL, 0); |
824 | |
|
825 | 0 | tor_assert(conn->base_.purpose != DIR_PURPOSE_FETCH_EXTRAINFO); |
826 | 0 | if (smartlist_len(which)) { |
827 | 0 | connection_dir_retry_bridges(which); |
828 | 0 | SMARTLIST_FOREACH(which, char *, cp, tor_free(cp)); |
829 | 0 | } |
830 | 0 | smartlist_free(which); |
831 | 0 | } |
832 | | |
833 | | /** Called when an attempt to fetch a certificate fails. */ |
834 | | static void |
835 | | connection_dir_download_cert_failed(dir_connection_t *conn, int status) |
836 | 0 | { |
837 | 0 | const char *fp_pfx = "fp/"; |
838 | 0 | const char *fpsk_pfx = "fp-sk/"; |
839 | 0 | smartlist_t *failed; |
840 | 0 | tor_assert(conn->base_.purpose == DIR_PURPOSE_FETCH_CERTIFICATE); |
841 | |
|
842 | 0 | if (!conn->requested_resource) |
843 | 0 | return; |
844 | 0 | failed = smartlist_new(); |
845 | | /* |
846 | | * We have two cases download by fingerprint (resource starts |
847 | | * with "fp/") or download by fingerprint/signing key pair |
848 | | * (resource starts with "fp-sk/"). |
849 | | */ |
850 | 0 | if (!strcmpstart(conn->requested_resource, fp_pfx)) { |
851 | | /* Download by fingerprint case */ |
852 | 0 | dir_split_resource_into_fingerprints(conn->requested_resource + |
853 | 0 | strlen(fp_pfx), |
854 | 0 | failed, NULL, DSR_HEX); |
855 | 0 | SMARTLIST_FOREACH_BEGIN(failed, char *, cp) { |
856 | | /* Null signing key digest indicates download by fp only */ |
857 | 0 | authority_cert_dl_failed(cp, NULL, status); |
858 | 0 | tor_free(cp); |
859 | 0 | } SMARTLIST_FOREACH_END(cp); |
860 | 0 | } else if (!strcmpstart(conn->requested_resource, fpsk_pfx)) { |
861 | | /* Download by (fp,sk) pairs */ |
862 | 0 | dir_split_resource_into_fingerprint_pairs(conn->requested_resource + |
863 | 0 | strlen(fpsk_pfx), failed); |
864 | 0 | SMARTLIST_FOREACH_BEGIN(failed, fp_pair_t *, cp) { |
865 | 0 | authority_cert_dl_failed(cp->first, cp->second, status); |
866 | 0 | tor_free(cp); |
867 | 0 | } SMARTLIST_FOREACH_END(cp); |
868 | 0 | } else { |
869 | 0 | log_warn(LD_DIR, |
870 | 0 | "Don't know what to do with failure for cert fetch %s", |
871 | 0 | conn->requested_resource); |
872 | 0 | } |
873 | |
|
874 | 0 | smartlist_free(failed); |
875 | |
|
876 | 0 | update_certificate_downloads(time(NULL)); |
877 | 0 | } |
878 | | |
879 | | /** Evaluate the situation and decide if we should use an encrypted |
880 | | * "begindir-style" connection for this directory request. |
881 | | * 0) If there is no DirPort, yes. |
882 | | * 1) If or_port is 0, or it's a direct conn and or_port is firewalled |
883 | | * or we're a dir mirror, no. |
884 | | * 2) If we prefer to avoid begindir conns, and we're not fetching or |
885 | | * publishing a bridge relay descriptor, no. |
886 | | * 3) Else yes. |
887 | | * If returning 0, return in *reason why we can't use begindir. |
888 | | * reason must not be NULL. |
889 | | */ |
890 | | static int |
891 | | directory_command_should_use_begindir(const or_options_t *options, |
892 | | const directory_request_t *req, |
893 | | const char **reason) |
894 | 0 | { |
895 | 0 | const tor_addr_t *or_addr = &req->or_addr_port.addr; |
896 | | //const tor_addr_t *dir_addr = &req->dir_addr_port.addr; |
897 | 0 | const int or_port = req->or_addr_port.port; |
898 | 0 | const int dir_port = req->dir_addr_port.port; |
899 | |
|
900 | 0 | const dir_indirection_t indirection = req->indirection; |
901 | |
|
902 | 0 | tor_assert(reason); |
903 | 0 | *reason = NULL; |
904 | | |
905 | | /* Reasons why we must use begindir */ |
906 | 0 | if (!dir_port) { |
907 | 0 | *reason = "(using begindir - directory with no DirPort)"; |
908 | 0 | return 1; /* We don't know a DirPort -- must begindir. */ |
909 | 0 | } |
910 | | /* Reasons why we can't possibly use begindir */ |
911 | 0 | if (!or_port) { |
912 | 0 | *reason = "directory with unknown ORPort"; |
913 | 0 | return 0; /* We don't know an ORPort -- no chance. */ |
914 | 0 | } |
915 | 0 | if (indirection == DIRIND_DIRECT_CONN || |
916 | 0 | indirection == DIRIND_ANON_DIRPORT) { |
917 | 0 | *reason = "DirPort connection"; |
918 | 0 | return 0; |
919 | 0 | } |
920 | 0 | if (indirection == DIRIND_ONEHOP) { |
921 | | /* We're firewalled and want a direct OR connection */ |
922 | 0 | if (!reachable_addr_allows_addr(or_addr, or_port, |
923 | 0 | FIREWALL_OR_CONNECTION, 0, 0)) { |
924 | 0 | *reason = "ORPort not reachable"; |
925 | 0 | return 0; |
926 | 0 | } |
927 | 0 | } |
928 | | /* Reasons why we want to avoid using begindir */ |
929 | 0 | if (indirection == DIRIND_ONEHOP) { |
930 | 0 | if (!dirclient_must_use_begindir(options)) { |
931 | 0 | *reason = "in relay mode"; |
932 | 0 | return 0; |
933 | 0 | } |
934 | 0 | } |
935 | | /* DIRIND_ONEHOP on a client, or DIRIND_ANONYMOUS |
936 | | */ |
937 | 0 | *reason = "(using begindir)"; |
938 | 0 | return 1; |
939 | 0 | } |
940 | | |
941 | | /** |
942 | | * Create and return a new directory_request_t with purpose |
943 | | * <b>dir_purpose</b>. |
944 | | */ |
945 | | directory_request_t * |
946 | | directory_request_new(uint8_t dir_purpose) |
947 | 0 | { |
948 | 0 | tor_assert(dir_purpose >= DIR_PURPOSE_MIN_); |
949 | 0 | tor_assert(dir_purpose <= DIR_PURPOSE_MAX_); |
950 | 0 | tor_assert(dir_purpose != DIR_PURPOSE_SERVER); |
951 | 0 | tor_assert(dir_purpose != DIR_PURPOSE_HAS_FETCHED_HSDESC); |
952 | |
|
953 | 0 | directory_request_t *result = tor_malloc_zero(sizeof(*result)); |
954 | 0 | tor_addr_make_null(&result->or_addr_port.addr, AF_INET); |
955 | 0 | result->or_addr_port.port = 0; |
956 | 0 | tor_addr_make_null(&result->dir_addr_port.addr, AF_INET); |
957 | 0 | result->dir_addr_port.port = 0; |
958 | 0 | result->dir_purpose = dir_purpose; |
959 | 0 | result->router_purpose = ROUTER_PURPOSE_GENERAL; |
960 | 0 | result->indirection = DIRIND_ONEHOP; |
961 | 0 | return result; |
962 | 0 | } |
963 | | /** |
964 | | * Release all resources held by <b>req</b>. |
965 | | */ |
966 | | void |
967 | | directory_request_free_(directory_request_t *req) |
968 | 0 | { |
969 | 0 | if (req == NULL) |
970 | 0 | return; |
971 | 0 | config_free_lines(req->additional_headers); |
972 | 0 | tor_free(req); |
973 | 0 | } |
974 | | /** |
975 | | * Set the address and OR port to use for this directory request. If there is |
976 | | * no OR port, we'll have to connect over the dirport. (If there are both, |
977 | | * the indirection setting determines which to use.) |
978 | | */ |
979 | | void |
980 | | directory_request_set_or_addr_port(directory_request_t *req, |
981 | | const tor_addr_port_t *p) |
982 | 0 | { |
983 | 0 | memcpy(&req->or_addr_port, p, sizeof(*p)); |
984 | 0 | } |
985 | | /** |
986 | | * Set the address and dirport to use for this directory request. If there |
987 | | * is no dirport, we'll have to connect over the OR port. (If there are both, |
988 | | * the indirection setting determines which to use.) |
989 | | */ |
990 | | void |
991 | | directory_request_set_dir_addr_port(directory_request_t *req, |
992 | | const tor_addr_port_t *p) |
993 | 0 | { |
994 | 0 | memcpy(&req->dir_addr_port, p, sizeof(*p)); |
995 | 0 | } |
996 | | /** |
997 | | * Set the RSA identity digest of the directory to use for this directory |
998 | | * request. |
999 | | */ |
1000 | | void |
1001 | | directory_request_set_directory_id_digest(directory_request_t *req, |
1002 | | const char *digest) |
1003 | 0 | { |
1004 | 0 | memcpy(req->digest, digest, DIGEST_LEN); |
1005 | 0 | } |
1006 | | /** |
1007 | | * Set the router purpose associated with uploaded and downloaded router |
1008 | | * descriptors and extrainfo documents in this directory request. The purpose |
1009 | | * must be one of ROUTER_PURPOSE_GENERAL (the default) or |
1010 | | * ROUTER_PURPOSE_BRIDGE. |
1011 | | */ |
1012 | | void |
1013 | | directory_request_set_router_purpose(directory_request_t *req, |
1014 | | uint8_t router_purpose) |
1015 | 0 | { |
1016 | 0 | tor_assert(router_purpose == ROUTER_PURPOSE_GENERAL || |
1017 | 0 | router_purpose == ROUTER_PURPOSE_BRIDGE); |
1018 | | // assert that it actually makes sense to set this purpose, given |
1019 | | // the dir_purpose. |
1020 | 0 | req->router_purpose = router_purpose; |
1021 | 0 | } |
1022 | | /** |
1023 | | * Set the indirection to be used for the directory request. The indirection |
1024 | | * parameter configures whether to connect to a DirPort or ORPort, and whether |
1025 | | * to anonymize the connection. DIRIND_ONEHOP (use ORPort, don't anonymize) |
1026 | | * is the default. See dir_indirection_t for more information. |
1027 | | */ |
1028 | | void |
1029 | | directory_request_set_indirection(directory_request_t *req, |
1030 | | dir_indirection_t indirection) |
1031 | 0 | { |
1032 | 0 | req->indirection = indirection; |
1033 | 0 | } |
1034 | | |
1035 | | /** |
1036 | | * Set a pointer to the resource to request from a directory. Different |
1037 | | * request types use resources to indicate different components of their URL. |
1038 | | * Note that only an alias to <b>resource</b> is stored, so the |
1039 | | * <b>resource</b> must outlive the request. |
1040 | | */ |
1041 | | void |
1042 | | directory_request_set_resource(directory_request_t *req, |
1043 | | const char *resource) |
1044 | 0 | { |
1045 | 0 | req->resource = resource; |
1046 | 0 | } |
1047 | | /** |
1048 | | * Set a pointer to the payload to include with this directory request, along |
1049 | | * with its length. Note that only an alias to <b>payload</b> is stored, so |
1050 | | * the <b>payload</b> must outlive the request. |
1051 | | */ |
1052 | | void |
1053 | | directory_request_set_payload(directory_request_t *req, |
1054 | | const char *payload, |
1055 | | size_t payload_len) |
1056 | 0 | { |
1057 | 0 | tor_assert(DIR_PURPOSE_IS_UPLOAD(req->dir_purpose)); |
1058 | |
|
1059 | 0 | req->payload = payload; |
1060 | 0 | req->payload_len = payload_len; |
1061 | 0 | } |
1062 | | /** |
1063 | | * Set an if-modified-since date to send along with the request. The |
1064 | | * default is 0 (meaning, send no if-modified-since header). |
1065 | | */ |
1066 | | void |
1067 | | directory_request_set_if_modified_since(directory_request_t *req, |
1068 | | time_t if_modified_since) |
1069 | 0 | { |
1070 | 0 | req->if_modified_since = if_modified_since; |
1071 | 0 | } |
1072 | | |
1073 | | /** Include a header of name <b>key</b> with content <b>val</b> in the |
1074 | | * request. Neither may include newlines or other odd characters. Their |
1075 | | * ordering is not currently guaranteed. |
1076 | | * |
1077 | | * Note that, as elsewhere in this module, header keys include a trailing |
1078 | | * colon and space. |
1079 | | */ |
1080 | | void |
1081 | | directory_request_add_header(directory_request_t *req, |
1082 | | const char *key, |
1083 | | const char *val) |
1084 | 0 | { |
1085 | 0 | config_line_prepend(&req->additional_headers, key, val); |
1086 | 0 | } |
1087 | | /** |
1088 | | * Set an object containing HS connection identifier to be associated with |
1089 | | * this request. Note that only an alias to <b>ident</b> is stored, so the |
1090 | | * <b>ident</b> object must outlive the request. |
1091 | | */ |
1092 | | void |
1093 | | directory_request_upload_set_hs_ident(directory_request_t *req, |
1094 | | const hs_ident_dir_conn_t *ident) |
1095 | 0 | { |
1096 | 0 | if (ident) { |
1097 | 0 | tor_assert(req->dir_purpose == DIR_PURPOSE_UPLOAD_HSDESC); |
1098 | 0 | } |
1099 | 0 | req->hs_ident = ident; |
1100 | 0 | } |
1101 | | /** |
1102 | | * Set an object containing HS connection identifier to be associated with |
1103 | | * this fetch request. Note that only an alias to <b>ident</b> is stored, so |
1104 | | * the <b>ident</b> object must outlive the request. |
1105 | | */ |
1106 | | void |
1107 | | directory_request_fetch_set_hs_ident(directory_request_t *req, |
1108 | | const hs_ident_dir_conn_t *ident) |
1109 | 0 | { |
1110 | 0 | if (ident) { |
1111 | 0 | tor_assert(req->dir_purpose == DIR_PURPOSE_FETCH_HSDESC); |
1112 | 0 | } |
1113 | 0 | req->hs_ident = ident; |
1114 | 0 | } |
1115 | | /** Set a static circuit_guard_state_t object to affliate with the request in |
1116 | | * <b>req</b>. This object will receive notification when the attempt to |
1117 | | * connect to the guard either succeeds or fails. */ |
1118 | | void |
1119 | | directory_request_set_guard_state(directory_request_t *req, |
1120 | | circuit_guard_state_t *state) |
1121 | 0 | { |
1122 | 0 | req->guard_state = state; |
1123 | 0 | } |
1124 | | |
1125 | | /** |
1126 | | * Internal: Return true if any information for contacting the directory in |
1127 | | * <b>req</b> has been set, other than by the routerstatus. */ |
1128 | | static int |
1129 | | directory_request_dir_contact_info_specified(const directory_request_t *req) |
1130 | 0 | { |
1131 | | /* We only check for ports here, since we don't use an addr unless the port |
1132 | | * is set */ |
1133 | 0 | return (req->or_addr_port.port || |
1134 | 0 | req->dir_addr_port.port || |
1135 | 0 | ! tor_digest_is_zero(req->digest)); |
1136 | 0 | } |
1137 | | |
1138 | | /** |
1139 | | * Set the routerstatus to use for the directory associated with this |
1140 | | * request. If this option is set, then no other function to set the |
1141 | | * directory's address or identity should be called. |
1142 | | */ |
1143 | | void |
1144 | | directory_request_set_routerstatus(directory_request_t *req, |
1145 | | const routerstatus_t *status) |
1146 | 0 | { |
1147 | 0 | req->routerstatus = status; |
1148 | 0 | } |
1149 | | |
1150 | | /** |
1151 | | * Helper: update the addresses, ports, and identities in <b>req</b> |
1152 | | * from the routerstatus object in <b>req</b>. Return 0 on success. |
1153 | | * On failure, warn and return -1. |
1154 | | */ |
1155 | | static int |
1156 | | directory_request_set_dir_from_routerstatus(directory_request_t *req) |
1157 | | |
1158 | 0 | { |
1159 | 0 | const routerstatus_t *status = req->routerstatus; |
1160 | 0 | if (BUG(status == NULL)) |
1161 | 0 | return -1; |
1162 | 0 | const or_options_t *options = get_options(); |
1163 | 0 | const node_t *node; |
1164 | 0 | tor_addr_port_t use_or_ap, use_dir_ap; |
1165 | 0 | const int anonymized_connection = dirind_is_anon(req->indirection); |
1166 | |
|
1167 | 0 | tor_assert(status != NULL); |
1168 | |
|
1169 | 0 | node = node_get_by_id(status->identity_digest); |
1170 | | |
1171 | | /* XXX The below check is wrong: !node means it's not in the consensus, |
1172 | | * but we haven't checked if we have a descriptor for it -- and also, |
1173 | | * we only care about the descriptor if it's a begindir-style anonymized |
1174 | | * connection. */ |
1175 | 0 | if (!node && anonymized_connection) { |
1176 | 0 | log_info(LD_DIR, "Not sending anonymized request to directory '%s'; we " |
1177 | 0 | "don't have its router descriptor.", |
1178 | 0 | routerstatus_describe(status)); |
1179 | 0 | return -1; |
1180 | 0 | } |
1181 | | |
1182 | 0 | if (options->ExcludeNodes && options->StrictNodes && |
1183 | 0 | routerset_contains_routerstatus(options->ExcludeNodes, status, -1)) { |
1184 | 0 | log_warn(LD_DIR, "Wanted to contact directory mirror %s for %s, but " |
1185 | 0 | "it's in our ExcludedNodes list and StrictNodes is set. " |
1186 | 0 | "Skipping. This choice might make your Tor not work.", |
1187 | 0 | routerstatus_describe(status), |
1188 | 0 | dir_conn_purpose_to_string(req->dir_purpose)); |
1189 | 0 | return -1; |
1190 | 0 | } |
1191 | | |
1192 | | /* At this point, if we are a client making a direct connection to a |
1193 | | * directory server, we have selected a server that has at least one address |
1194 | | * allowed by ClientUseIPv4/6 and Reachable{"",OR,Dir}Addresses. This |
1195 | | * selection uses the preference in ClientPreferIPv6{OR,Dir}Port, if |
1196 | | * possible. (If UseBridges is set, clients always use IPv6, and prefer it |
1197 | | * by default.) |
1198 | | * |
1199 | | * Now choose an address that we can use to connect to the directory server. |
1200 | | */ |
1201 | 0 | if (directory_choose_address_routerstatus(status, |
1202 | 0 | req->indirection, &use_or_ap, |
1203 | 0 | &use_dir_ap) < 0) { |
1204 | 0 | return -1; |
1205 | 0 | } |
1206 | | |
1207 | | /* One last thing: If we're talking to an authority, we might want to use |
1208 | | * a special HTTP port for it based on our purpose. |
1209 | | */ |
1210 | 0 | if (req->indirection == DIRIND_DIRECT_CONN && status->is_authority) { |
1211 | 0 | const dir_server_t *ds = router_get_trusteddirserver_by_digest( |
1212 | 0 | status->identity_digest); |
1213 | 0 | if (ds) { |
1214 | 0 | const tor_addr_port_t *v4 = NULL; |
1215 | 0 | if (authdir_mode_v3(get_options())) { |
1216 | | // An authority connecting to another authority should always |
1217 | | // prefer the VOTING usage, if one is specifically configured. |
1218 | 0 | v4 = trusted_dir_server_get_dirport_exact( |
1219 | 0 | ds, AUTH_USAGE_VOTING, AF_INET); |
1220 | 0 | } |
1221 | 0 | if (! v4) { |
1222 | | // Everybody else should prefer a usage dependent on their |
1223 | | // the dir_purpose. |
1224 | 0 | auth_dirport_usage_t usage = |
1225 | 0 | auth_dirport_usage_for_purpose(req->dir_purpose); |
1226 | 0 | v4 = trusted_dir_server_get_dirport(ds, usage, AF_INET); |
1227 | 0 | } |
1228 | 0 | tor_assert_nonfatal(v4); |
1229 | 0 | if (v4) { |
1230 | | // XXXX We could, if we wanted, also select a v6 address. But a v4 |
1231 | | // address must exist here, and we as a relay are required to support |
1232 | | // ipv4. So we just that. |
1233 | 0 | tor_addr_port_copy(&use_dir_ap, v4); |
1234 | 0 | } |
1235 | 0 | } |
1236 | 0 | } |
1237 | |
|
1238 | 0 | directory_request_set_or_addr_port(req, &use_or_ap); |
1239 | 0 | directory_request_set_dir_addr_port(req, &use_dir_ap); |
1240 | 0 | directory_request_set_directory_id_digest(req, status->identity_digest); |
1241 | 0 | return 0; |
1242 | 0 | } |
1243 | | |
1244 | | /** |
1245 | | * Launch the provided directory request, configured in <b>request</b>. |
1246 | | * After this function is called, you can free <b>request</b>. |
1247 | | */ |
1248 | | MOCK_IMPL(void, |
1249 | | directory_initiate_request,(directory_request_t *request)) |
1250 | 0 | { |
1251 | 0 | tor_assert(request); |
1252 | 0 | if (request->routerstatus) { |
1253 | 0 | tor_assert_nonfatal( |
1254 | 0 | ! directory_request_dir_contact_info_specified(request)); |
1255 | 0 | if (directory_request_set_dir_from_routerstatus(request) < 0) { |
1256 | 0 | return; // or here XXXX |
1257 | 0 | } |
1258 | 0 | } |
1259 | | |
1260 | 0 | const tor_addr_port_t *or_addr_port = &request->or_addr_port; |
1261 | 0 | const tor_addr_port_t *dir_addr_port = &request->dir_addr_port; |
1262 | 0 | const char *digest = request->digest; |
1263 | 0 | const uint8_t dir_purpose = request->dir_purpose; |
1264 | 0 | const uint8_t router_purpose = request->router_purpose; |
1265 | 0 | const dir_indirection_t indirection = request->indirection; |
1266 | 0 | const char *resource = request->resource; |
1267 | 0 | const hs_ident_dir_conn_t *hs_ident = request->hs_ident; |
1268 | 0 | circuit_guard_state_t *guard_state = request->guard_state; |
1269 | |
|
1270 | 0 | tor_assert(or_addr_port->port || dir_addr_port->port); |
1271 | 0 | tor_assert(digest); |
1272 | |
|
1273 | 0 | dir_connection_t *conn; |
1274 | 0 | const or_options_t *options = get_options(); |
1275 | 0 | int socket_error = 0; |
1276 | 0 | const char *begindir_reason = NULL; |
1277 | | /* Should the connection be to a relay's OR port (and inside that we will |
1278 | | * send our directory request)? */ |
1279 | 0 | const int use_begindir = |
1280 | 0 | directory_command_should_use_begindir(options, request, &begindir_reason); |
1281 | | |
1282 | | /* Will the connection go via a three-hop Tor circuit? Note that this |
1283 | | * is separate from whether it will use_begindir. */ |
1284 | 0 | const int anonymized_connection = dirind_is_anon(indirection); |
1285 | | |
1286 | | /* What is the address we want to make the directory request to? If |
1287 | | * we're making a begindir request this is the ORPort of the relay |
1288 | | * we're contacting; if not a begindir request, this is its DirPort. |
1289 | | * Note that if anonymized_connection is true, we won't be initiating |
1290 | | * a connection directly to this address. */ |
1291 | 0 | tor_addr_t addr; |
1292 | 0 | tor_addr_copy(&addr, &(use_begindir ? or_addr_port : dir_addr_port)->addr); |
1293 | 0 | uint16_t port = (use_begindir ? or_addr_port : dir_addr_port)->port; |
1294 | |
|
1295 | 0 | log_debug(LD_DIR, "anonymized %d, use_begindir %d.", |
1296 | 0 | anonymized_connection, use_begindir); |
1297 | |
|
1298 | 0 | log_debug(LD_DIR, "Initiating %s", dir_conn_purpose_to_string(dir_purpose)); |
1299 | |
|
1300 | 0 | if (purpose_needs_anonymity(dir_purpose, router_purpose, resource)) { |
1301 | 0 | tor_assert(anonymized_connection || |
1302 | 0 | hs_service_non_anonymous_mode_enabled(options)); |
1303 | 0 | } |
1304 | | |
1305 | | /* use encrypted begindir connections for everything except relays |
1306 | | * this provides better protection for directory fetches */ |
1307 | 0 | if (!use_begindir && dirclient_must_use_begindir(options)) { |
1308 | 0 | log_warn(LD_BUG, "Client could not use begindir connection: %s", |
1309 | 0 | begindir_reason ? begindir_reason : "(NULL)"); |
1310 | 0 | return; |
1311 | 0 | } |
1312 | | |
1313 | | /* ensure that we don't make direct connections when a SOCKS server is |
1314 | | * configured. */ |
1315 | 0 | if (!anonymized_connection && !use_begindir && !options->HTTPProxy && |
1316 | 0 | (options->Socks4Proxy || options->Socks5Proxy)) { |
1317 | 0 | log_warn(LD_DIR, "Cannot connect to a directory server through a " |
1318 | 0 | "SOCKS proxy!"); |
1319 | 0 | return; |
1320 | 0 | } |
1321 | | |
1322 | | /* Make sure that the destination addr and port we picked is viable. */ |
1323 | 0 | if (!port || tor_addr_is_null(&addr)) { |
1324 | 0 | log_warn(LD_DIR, |
1325 | 0 | "Cannot make an outgoing %sconnection without a remote %sPort.", |
1326 | 0 | use_begindir ? "begindir " : "", |
1327 | 0 | use_begindir ? "OR" : "Dir"); |
1328 | 0 | log_backtrace_once(LOG_INFO, LD_BUG, "Address came from"); |
1329 | 0 | return; |
1330 | 0 | } |
1331 | | |
1332 | 0 | conn = dir_connection_new(tor_addr_family(&addr)); |
1333 | | |
1334 | | /* set up conn so it's got all the data we need to remember */ |
1335 | 0 | tor_addr_copy(&conn->base_.addr, &addr); |
1336 | 0 | conn->base_.port = port; |
1337 | 0 | conn->base_.address = tor_addr_to_str_dup(&addr); |
1338 | 0 | memcpy(conn->identity_digest, digest, DIGEST_LEN); |
1339 | |
|
1340 | 0 | conn->base_.purpose = dir_purpose; |
1341 | 0 | conn->router_purpose = router_purpose; |
1342 | | |
1343 | | /* give it an initial state */ |
1344 | 0 | conn->base_.state = DIR_CONN_STATE_CONNECTING; |
1345 | | |
1346 | | /* decide whether we can learn our IP address from this conn */ |
1347 | | /* XXXX This is a bad name for this field now. */ |
1348 | 0 | conn->dirconn_direct = !anonymized_connection; |
1349 | |
|
1350 | 0 | if (hs_ident) { |
1351 | 0 | conn->hs_ident = hs_ident_dir_conn_dup(hs_ident); |
1352 | 0 | } |
1353 | |
|
1354 | 0 | if (!anonymized_connection && !use_begindir) { |
1355 | | /* then we want to connect to dirport directly */ |
1356 | |
|
1357 | 0 | if (options->HTTPProxy) { |
1358 | 0 | tor_addr_copy(&addr, &options->HTTPProxyAddr); |
1359 | 0 | port = options->HTTPProxyPort; |
1360 | 0 | } |
1361 | | |
1362 | | // In this case we should not have picked a directory guard. |
1363 | 0 | if (BUG(guard_state)) { |
1364 | 0 | entry_guard_cancel(&guard_state); |
1365 | 0 | } |
1366 | | |
1367 | | // XXXX This is the case where we replace. |
1368 | |
|
1369 | 0 | switch (connection_connect(TO_CONN(conn), conn->base_.address, &addr, |
1370 | 0 | port, &socket_error)) { |
1371 | 0 | case -1: |
1372 | 0 | connection_mark_for_close(TO_CONN(conn)); |
1373 | 0 | return; |
1374 | 0 | case 1: |
1375 | | /* start flushing conn */ |
1376 | 0 | conn->base_.state = DIR_CONN_STATE_CLIENT_SENDING; |
1377 | 0 | FALLTHROUGH; |
1378 | 0 | case 0: |
1379 | | /* queue the command on the outbuf */ |
1380 | 0 | directory_send_command(conn, 1, request); |
1381 | 0 | connection_watch_events(TO_CONN(conn), READ_EVENT | WRITE_EVENT); |
1382 | | /* writable indicates finish, readable indicates broken link, |
1383 | | error indicates broken link in windowsland. */ |
1384 | 0 | } |
1385 | 0 | } else { |
1386 | | /* We will use a Tor circuit (maybe 1-hop, maybe 3-hop, maybe with |
1387 | | * begindir, maybe not with begindir) */ |
1388 | |
|
1389 | 0 | entry_connection_t *linked_conn; |
1390 | | |
1391 | | /* Anonymized tunneled connections can never share a circuit. |
1392 | | * One-hop directory connections can share circuits with each other |
1393 | | * but nothing else. */ |
1394 | 0 | int iso_flags = anonymized_connection ? ISO_STREAM : ISO_SESSIONGRP; |
1395 | | |
1396 | | /* If it's an anonymized connection, remember the fact that we |
1397 | | * wanted it for later: maybe we'll want it again soon. */ |
1398 | 0 | if (anonymized_connection && use_begindir) |
1399 | 0 | rep_hist_note_used_internal(time(NULL), 0, 1); |
1400 | 0 | else if (anonymized_connection && !use_begindir) |
1401 | 0 | rep_hist_note_used_port(time(NULL), conn->base_.port); |
1402 | | |
1403 | | // In this case we should not have a directory guard; we'll |
1404 | | // get a regular guard later when we build the circuit. |
1405 | 0 | if (BUG(anonymized_connection && guard_state)) { |
1406 | 0 | entry_guard_cancel(&guard_state); |
1407 | 0 | } |
1408 | |
|
1409 | 0 | conn->guard_state = guard_state; |
1410 | | |
1411 | | /* make an AP connection |
1412 | | * populate it and add it at the right state |
1413 | | * hook up both sides |
1414 | | */ |
1415 | 0 | linked_conn = |
1416 | 0 | connection_ap_make_link(TO_CONN(conn), |
1417 | 0 | conn->base_.address, conn->base_.port, |
1418 | 0 | digest, |
1419 | 0 | SESSION_GROUP_DIRCONN, iso_flags, |
1420 | 0 | use_begindir, !anonymized_connection); |
1421 | 0 | if (!linked_conn) { |
1422 | 0 | log_warn(LD_NET,"Making tunnel to dirserver failed."); |
1423 | 0 | connection_mark_for_close(TO_CONN(conn)); |
1424 | 0 | return; |
1425 | 0 | } |
1426 | | |
1427 | 0 | if (connection_add(TO_CONN(conn)) < 0) { |
1428 | 0 | log_warn(LD_NET,"Unable to add connection for link to dirserver."); |
1429 | 0 | connection_mark_for_close(TO_CONN(conn)); |
1430 | 0 | return; |
1431 | 0 | } |
1432 | 0 | conn->base_.state = DIR_CONN_STATE_CLIENT_SENDING; |
1433 | | /* queue the command on the outbuf */ |
1434 | 0 | directory_send_command(conn, 0, request); |
1435 | |
|
1436 | 0 | connection_watch_events(TO_CONN(conn), READ_EVENT|WRITE_EVENT); |
1437 | 0 | connection_start_reading(ENTRY_TO_CONN(linked_conn)); |
1438 | 0 | } |
1439 | 0 | } |
1440 | | |
1441 | | /** Helper for sorting |
1442 | | * |
1443 | | * sort strings alphabetically |
1444 | | * |
1445 | | * XXXX we have a smartlist_sort_strings() function, right? |
1446 | | */ |
1447 | | static int |
1448 | | compare_strs_(const void **a, const void **b) |
1449 | 0 | { |
1450 | 0 | const char *s1 = *a, *s2 = *b; |
1451 | 0 | return strcmp(s1, s2); |
1452 | 0 | } |
1453 | | |
1454 | 0 | #define CONDITIONAL_CONSENSUS_FPR_LEN 3 |
1455 | | CTASSERT(CONDITIONAL_CONSENSUS_FPR_LEN <= DIGEST_LEN); |
1456 | | |
1457 | | /** Return the URL we should use for a consensus download. |
1458 | | * |
1459 | | * Use the "conditional consensus downloading" feature described in |
1460 | | * dir-spec.txt, i.e. |
1461 | | * GET .../consensus/<b>fpr</b>+<b>fpr</b>+<b>fpr</b> |
1462 | | * |
1463 | | * If 'resource' is provided, it is the name of a consensus flavor to request. |
1464 | | */ |
1465 | | static char * |
1466 | | directory_get_consensus_url(const char *resource) |
1467 | 0 | { |
1468 | 0 | char *url = NULL; |
1469 | 0 | const char *hyphen, *flavor; |
1470 | 0 | if (resource==NULL || strcmp(resource, "ns")==0) { |
1471 | 0 | flavor = ""; /* Request ns consensuses as "", so older servers will work*/ |
1472 | 0 | hyphen = ""; |
1473 | 0 | } else { |
1474 | 0 | flavor = resource; |
1475 | 0 | hyphen = "-"; |
1476 | 0 | } |
1477 | |
|
1478 | 0 | { |
1479 | 0 | char *authority_id_list; |
1480 | 0 | smartlist_t *authority_digests = smartlist_new(); |
1481 | |
|
1482 | 0 | SMARTLIST_FOREACH_BEGIN(router_get_trusted_dir_servers(), |
1483 | 0 | dir_server_t *, ds) { |
1484 | 0 | char *hex; |
1485 | 0 | if (!(ds->type & V3_DIRINFO)) |
1486 | 0 | continue; |
1487 | | |
1488 | 0 | hex = tor_malloc(2*CONDITIONAL_CONSENSUS_FPR_LEN+1); |
1489 | 0 | base16_encode(hex, 2*CONDITIONAL_CONSENSUS_FPR_LEN+1, |
1490 | 0 | ds->v3_identity_digest, CONDITIONAL_CONSENSUS_FPR_LEN); |
1491 | 0 | smartlist_add(authority_digests, hex); |
1492 | 0 | } SMARTLIST_FOREACH_END(ds); |
1493 | 0 | smartlist_sort(authority_digests, compare_strs_); |
1494 | 0 | authority_id_list = smartlist_join_strings(authority_digests, |
1495 | 0 | "+", 0, NULL); |
1496 | |
|
1497 | 0 | tor_asprintf(&url, "/tor/status-vote/current/consensus%s%s/%s.z", |
1498 | 0 | hyphen, flavor, authority_id_list); |
1499 | |
|
1500 | 0 | SMARTLIST_FOREACH(authority_digests, char *, cp, tor_free(cp)); |
1501 | 0 | smartlist_free(authority_digests); |
1502 | 0 | tor_free(authority_id_list); |
1503 | 0 | } |
1504 | 0 | return url; |
1505 | 0 | } |
1506 | | |
1507 | | /** |
1508 | | * Copies the ipv6 from source to destination, subject to buffer size limit |
1509 | | * size. If decorate is true, makes sure the copied address is decorated. |
1510 | | */ |
1511 | | static void |
1512 | | copy_ipv6_address(char* destination, const char* source, size_t len, |
1513 | 0 | int decorate) { |
1514 | 0 | tor_assert(destination); |
1515 | 0 | tor_assert(source); |
1516 | |
|
1517 | 0 | if (decorate && source[0] != '[') { |
1518 | 0 | tor_snprintf(destination, len, "[%s]", source); |
1519 | 0 | } else { |
1520 | 0 | strlcpy(destination, source, len); |
1521 | 0 | } |
1522 | 0 | } |
1523 | | |
1524 | | /** Queue an appropriate HTTP command for <b>request</b> on |
1525 | | * <b>conn</b>-\>outbuf. If <b>direct</b> is true, we're making a |
1526 | | * non-anonymized connection to the dirport. |
1527 | | */ |
1528 | | static void |
1529 | | directory_send_command(dir_connection_t *conn, |
1530 | | const int direct, |
1531 | | const directory_request_t *req) |
1532 | 0 | { |
1533 | 0 | tor_assert(req); |
1534 | 0 | const int purpose = req->dir_purpose; |
1535 | 0 | const char *resource = req->resource; |
1536 | 0 | const char *payload = req->payload; |
1537 | 0 | const size_t payload_len = req->payload_len; |
1538 | 0 | const time_t if_modified_since = req->if_modified_since; |
1539 | 0 | const int anonymized_connection = dirind_is_anon(req->indirection); |
1540 | |
|
1541 | 0 | char proxystring[256]; |
1542 | 0 | char hoststring[128]; |
1543 | | /* NEEDS to be the same size hoststring. |
1544 | | Will be decorated with brackets around it if it is ipv6. */ |
1545 | 0 | char decorated_address[128]; |
1546 | 0 | smartlist_t *headers = smartlist_new(); |
1547 | 0 | char *url; |
1548 | 0 | char *accept_encoding; |
1549 | 0 | size_t url_len; |
1550 | 0 | char request[8192]; |
1551 | 0 | size_t request_len, total_request_len = 0; |
1552 | 0 | const char *httpcommand = NULL; |
1553 | |
|
1554 | 0 | tor_assert(conn); |
1555 | 0 | tor_assert(conn->base_.type == CONN_TYPE_DIR); |
1556 | |
|
1557 | 0 | tor_free(conn->requested_resource); |
1558 | 0 | if (resource) |
1559 | 0 | conn->requested_resource = tor_strdup(resource); |
1560 | | |
1561 | | /* decorate the ip address if it is ipv6 */ |
1562 | 0 | if (strchr(conn->base_.address, ':')) { |
1563 | 0 | copy_ipv6_address(decorated_address, conn->base_.address, |
1564 | 0 | sizeof(decorated_address), 1); |
1565 | 0 | } else { |
1566 | 0 | strlcpy(decorated_address, conn->base_.address, sizeof(decorated_address)); |
1567 | 0 | } |
1568 | | |
1569 | | /* come up with a string for which Host: we want */ |
1570 | 0 | if (conn->base_.port == 80) { |
1571 | 0 | strlcpy(hoststring, decorated_address, sizeof(hoststring)); |
1572 | 0 | } else { |
1573 | 0 | tor_snprintf(hoststring, sizeof(hoststring), "%s:%d", |
1574 | 0 | decorated_address, conn->base_.port); |
1575 | 0 | } |
1576 | | |
1577 | | /* Format if-modified-since */ |
1578 | 0 | if (if_modified_since) { |
1579 | 0 | char b[RFC1123_TIME_LEN+1]; |
1580 | 0 | format_rfc1123_time(b, if_modified_since); |
1581 | 0 | smartlist_add_asprintf(headers, "If-Modified-Since: %s\r\n", b); |
1582 | 0 | } |
1583 | | |
1584 | | /* come up with some proxy lines, if we're using one. */ |
1585 | 0 | if (direct && get_options()->HTTPProxy) { |
1586 | 0 | char *base64_authenticator=NULL; |
1587 | 0 | const char *authenticator = get_options()->HTTPProxyAuthenticator; |
1588 | |
|
1589 | 0 | tor_snprintf(proxystring, sizeof(proxystring),"http://%s", hoststring); |
1590 | 0 | if (authenticator) { |
1591 | 0 | base64_authenticator = alloc_http_authenticator(authenticator); |
1592 | 0 | if (!base64_authenticator) |
1593 | 0 | log_warn(LD_BUG, "Encoding http authenticator failed"); |
1594 | 0 | } |
1595 | 0 | if (base64_authenticator) { |
1596 | 0 | smartlist_add_asprintf(headers, |
1597 | 0 | "Proxy-Authorization: Basic %s\r\n", |
1598 | 0 | base64_authenticator); |
1599 | 0 | tor_free(base64_authenticator); |
1600 | 0 | } |
1601 | 0 | } else { |
1602 | 0 | proxystring[0] = 0; |
1603 | 0 | } |
1604 | |
|
1605 | 0 | if (! anonymized_connection) { |
1606 | | /* Add Accept-Encoding. */ |
1607 | 0 | accept_encoding = accept_encoding_header(); |
1608 | 0 | smartlist_add_asprintf(headers, "Accept-Encoding: %s\r\n", |
1609 | 0 | accept_encoding); |
1610 | 0 | tor_free(accept_encoding); |
1611 | 0 | } |
1612 | | |
1613 | | /* Add additional headers, if any */ |
1614 | 0 | { |
1615 | 0 | config_line_t *h; |
1616 | 0 | for (h = req->additional_headers; h; h = h->next) { |
1617 | 0 | smartlist_add_asprintf(headers, "%s%s\r\n", h->key, h->value); |
1618 | 0 | } |
1619 | 0 | } |
1620 | |
|
1621 | 0 | switch (purpose) { |
1622 | 0 | case DIR_PURPOSE_FETCH_CONSENSUS: |
1623 | | /* resource is optional. If present, it's a flavor name */ |
1624 | 0 | tor_assert(!payload); |
1625 | 0 | httpcommand = "GET"; |
1626 | 0 | url = directory_get_consensus_url(resource); |
1627 | 0 | log_info(LD_DIR, "Downloading consensus from %s using %s", |
1628 | 0 | hoststring, url); |
1629 | 0 | break; |
1630 | 0 | case DIR_PURPOSE_FETCH_CERTIFICATE: |
1631 | 0 | tor_assert(resource); |
1632 | 0 | tor_assert(!payload); |
1633 | 0 | httpcommand = "GET"; |
1634 | 0 | tor_asprintf(&url, "/tor/keys/%s", resource); |
1635 | 0 | break; |
1636 | 0 | case DIR_PURPOSE_FETCH_STATUS_VOTE: |
1637 | 0 | tor_assert(resource); |
1638 | 0 | tor_assert(!payload); |
1639 | 0 | httpcommand = "GET"; |
1640 | 0 | tor_asprintf(&url, "/tor/status-vote/next/%s.z", resource); |
1641 | 0 | break; |
1642 | 0 | case DIR_PURPOSE_FETCH_DETACHED_SIGNATURES: |
1643 | 0 | tor_assert(!resource); |
1644 | 0 | tor_assert(!payload); |
1645 | 0 | httpcommand = "GET"; |
1646 | 0 | url = tor_strdup("/tor/status-vote/next/consensus-signatures.z"); |
1647 | 0 | break; |
1648 | 0 | case DIR_PURPOSE_FETCH_SERVERDESC: |
1649 | 0 | tor_assert(resource); |
1650 | 0 | httpcommand = "GET"; |
1651 | 0 | tor_asprintf(&url, "/tor/server/%s", resource); |
1652 | 0 | break; |
1653 | 0 | case DIR_PURPOSE_FETCH_EXTRAINFO: |
1654 | 0 | tor_assert(resource); |
1655 | 0 | httpcommand = "GET"; |
1656 | 0 | tor_asprintf(&url, "/tor/extra/%s", resource); |
1657 | 0 | break; |
1658 | 0 | case DIR_PURPOSE_FETCH_MICRODESC: |
1659 | 0 | tor_assert(resource); |
1660 | 0 | httpcommand = "GET"; |
1661 | 0 | tor_asprintf(&url, "/tor/micro/%s", resource); |
1662 | 0 | break; |
1663 | 0 | case DIR_PURPOSE_UPLOAD_DIR: { |
1664 | 0 | const char *why = router_get_descriptor_gen_reason(); |
1665 | 0 | tor_assert(!resource); |
1666 | 0 | tor_assert(payload); |
1667 | 0 | httpcommand = "POST"; |
1668 | 0 | url = tor_strdup("/tor/"); |
1669 | 0 | if (!why) { |
1670 | 0 | why = "for no reason at all"; |
1671 | 0 | } |
1672 | 0 | smartlist_add_asprintf(headers, "X-Desc-Gen-Reason: %s\r\n", why); |
1673 | 0 | break; |
1674 | 0 | } |
1675 | 0 | case DIR_PURPOSE_UPLOAD_VOTE: |
1676 | 0 | tor_assert(!resource); |
1677 | 0 | tor_assert(payload); |
1678 | 0 | httpcommand = "POST"; |
1679 | 0 | url = tor_strdup("/tor/post/vote"); |
1680 | 0 | break; |
1681 | 0 | case DIR_PURPOSE_UPLOAD_SIGNATURES: |
1682 | 0 | tor_assert(!resource); |
1683 | 0 | tor_assert(payload); |
1684 | 0 | httpcommand = "POST"; |
1685 | 0 | url = tor_strdup("/tor/post/consensus-signature"); |
1686 | 0 | break; |
1687 | 0 | case DIR_PURPOSE_FETCH_HSDESC: |
1688 | 0 | tor_assert(resource); |
1689 | 0 | tor_assert(strlen(resource) <= ED25519_BASE64_LEN); |
1690 | 0 | tor_assert(!payload); |
1691 | 0 | httpcommand = "GET"; |
1692 | 0 | tor_asprintf(&url, "/tor/hs/3/%s", resource); |
1693 | 0 | break; |
1694 | 0 | case DIR_PURPOSE_UPLOAD_HSDESC: |
1695 | 0 | tor_assert(resource); |
1696 | 0 | tor_assert(payload); |
1697 | 0 | httpcommand = "POST"; |
1698 | 0 | tor_asprintf(&url, "/tor/hs/%s/publish", resource); |
1699 | 0 | break; |
1700 | 0 | default: |
1701 | 0 | tor_assert(0); |
1702 | 0 | return; |
1703 | 0 | } |
1704 | | |
1705 | | /* warn in the non-tunneled case */ |
1706 | 0 | if (direct && (strlen(proxystring) + strlen(url) >= 4096)) { |
1707 | 0 | log_warn(LD_BUG, |
1708 | 0 | "Squid does not like URLs longer than 4095 bytes, and this " |
1709 | 0 | "one is %d bytes long: %s%s", |
1710 | 0 | (int)(strlen(proxystring) + strlen(url)), proxystring, url); |
1711 | 0 | } |
1712 | |
|
1713 | 0 | tor_snprintf(request, sizeof(request), "%s %s", httpcommand, proxystring); |
1714 | |
|
1715 | 0 | request_len = strlen(request); |
1716 | 0 | total_request_len += request_len; |
1717 | 0 | connection_buf_add(request, request_len, TO_CONN(conn)); |
1718 | |
|
1719 | 0 | url_len = strlen(url); |
1720 | 0 | total_request_len += url_len; |
1721 | 0 | connection_buf_add(url, url_len, TO_CONN(conn)); |
1722 | 0 | tor_free(url); |
1723 | |
|
1724 | 0 | if (!strcmp(httpcommand, "POST") || payload) { |
1725 | 0 | smartlist_add_asprintf(headers, "Content-Length: %lu\r\n", |
1726 | 0 | payload ? (unsigned long)payload_len : 0); |
1727 | 0 | } |
1728 | |
|
1729 | 0 | { |
1730 | 0 | char *header = smartlist_join_strings(headers, "", 0, NULL); |
1731 | 0 | tor_snprintf(request, sizeof(request), " HTTP/1.0\r\nHost: %s\r\n%s\r\n", |
1732 | 0 | hoststring, header); |
1733 | 0 | tor_free(header); |
1734 | 0 | } |
1735 | |
|
1736 | 0 | request_len = strlen(request); |
1737 | 0 | total_request_len += request_len; |
1738 | 0 | connection_buf_add(request, request_len, TO_CONN(conn)); |
1739 | |
|
1740 | 0 | if (payload) { |
1741 | | /* then send the payload afterwards too */ |
1742 | 0 | connection_buf_add(payload, payload_len, TO_CONN(conn)); |
1743 | 0 | total_request_len += payload_len; |
1744 | 0 | } |
1745 | |
|
1746 | 0 | SMARTLIST_FOREACH(headers, char *, h, tor_free(h)); |
1747 | 0 | smartlist_free(headers); |
1748 | |
|
1749 | 0 | log_debug(LD_DIR, |
1750 | 0 | "Sent request to directory server %s " |
1751 | 0 | "(purpose: %d, request size: %"TOR_PRIuSZ", " |
1752 | 0 | "payload size: %"TOR_PRIuSZ")", |
1753 | 0 | connection_describe_peer(TO_CONN(conn)), |
1754 | 0 | conn->base_.purpose, |
1755 | 0 | (total_request_len), |
1756 | 0 | (payload ? payload_len : 0)); |
1757 | 0 | } |
1758 | | |
1759 | | /** Return true iff <b>body</b> doesn't start with a plausible router or |
1760 | | * network-status or microdescriptor opening. This is a sign of possible |
1761 | | * compression. */ |
1762 | | static int |
1763 | | body_is_plausible(const char *body, size_t len, int purpose) |
1764 | 0 | { |
1765 | 0 | int i; |
1766 | 0 | if (len == 0) |
1767 | 0 | return 1; /* empty bodies don't need decompression */ |
1768 | 0 | if (len < 32) |
1769 | 0 | return 0; |
1770 | 0 | if (purpose == DIR_PURPOSE_FETCH_MICRODESC) { |
1771 | 0 | return (!strcmpstart(body,"onion-key")); |
1772 | 0 | } |
1773 | | |
1774 | 0 | if (!strcmpstart(body,"router") || |
1775 | 0 | !strcmpstart(body,"network-status")) |
1776 | 0 | return 1; |
1777 | 0 | for (i=0;i<32;++i) { |
1778 | 0 | if (!TOR_ISPRINT(body[i]) && !TOR_ISSPACE(body[i])) |
1779 | 0 | return 0; |
1780 | 0 | } |
1781 | | |
1782 | 0 | return 1; |
1783 | 0 | } |
1784 | | |
1785 | | /** Called when we've just fetched a bunch of router descriptors in |
1786 | | * <b>body</b>. The list <b>which</b>, if present, holds digests for |
1787 | | * descriptors we requested: descriptor digests if <b>descriptor_digests</b> |
1788 | | * is true, or identity digests otherwise. Parse the descriptors, validate |
1789 | | * them, and annotate them as having purpose <b>purpose</b> and as having been |
1790 | | * downloaded from <b>source</b>. |
1791 | | * |
1792 | | * Return the number of routers actually added. */ |
1793 | | static int |
1794 | | load_downloaded_routers(const char *body, smartlist_t *which, |
1795 | | int descriptor_digests, |
1796 | | int router_purpose, |
1797 | | const char *source) |
1798 | 0 | { |
1799 | 0 | char buf[256]; |
1800 | 0 | char time_buf[ISO_TIME_LEN+1]; |
1801 | 0 | int added = 0; |
1802 | 0 | int general = router_purpose == ROUTER_PURPOSE_GENERAL; |
1803 | 0 | format_iso_time(time_buf, time(NULL)); |
1804 | 0 | tor_assert(source); |
1805 | |
|
1806 | 0 | if (tor_snprintf(buf, sizeof(buf), |
1807 | 0 | "@downloaded-at %s\n" |
1808 | 0 | "@source %s\n" |
1809 | 0 | "%s%s%s", time_buf, escaped(source), |
1810 | 0 | !general ? "@purpose " : "", |
1811 | 0 | !general ? router_purpose_to_string(router_purpose) : "", |
1812 | 0 | !general ? "\n" : "")<0) |
1813 | 0 | return added; |
1814 | | |
1815 | 0 | added = router_load_routers_from_string(body, NULL, SAVED_NOWHERE, which, |
1816 | 0 | descriptor_digests, buf); |
1817 | 0 | if (added && general) |
1818 | 0 | control_event_boot_dir(BOOTSTRAP_STATUS_LOADING_DESCRIPTORS, |
1819 | 0 | count_loading_descriptors_progress()); |
1820 | 0 | return added; |
1821 | 0 | } |
1822 | | |
1823 | | static int handle_response_fetch_certificate(dir_connection_t *, |
1824 | | const response_handler_args_t *); |
1825 | | static int handle_response_fetch_status_vote(dir_connection_t *, |
1826 | | const response_handler_args_t *); |
1827 | | static int handle_response_fetch_detached_signatures(dir_connection_t *, |
1828 | | const response_handler_args_t *); |
1829 | | static int handle_response_fetch_desc(dir_connection_t *, |
1830 | | const response_handler_args_t *); |
1831 | | static int handle_response_upload_dir(dir_connection_t *, |
1832 | | const response_handler_args_t *); |
1833 | | static int handle_response_upload_vote(dir_connection_t *, |
1834 | | const response_handler_args_t *); |
1835 | | static int handle_response_upload_signatures(dir_connection_t *, |
1836 | | const response_handler_args_t *); |
1837 | | static int handle_response_upload_hsdesc(dir_connection_t *, |
1838 | | const response_handler_args_t *); |
1839 | | |
1840 | | static int |
1841 | | dir_client_decompress_response_body(char **bodyp, size_t *bodylenp, |
1842 | | dir_connection_t *conn, |
1843 | | compress_method_t compression, |
1844 | | int anonymized_connection) |
1845 | 0 | { |
1846 | 0 | int rv = 0; |
1847 | 0 | const char *body = *bodyp; |
1848 | 0 | size_t body_len = *bodylenp; |
1849 | 0 | int allow_partial = (conn->base_.purpose == DIR_PURPOSE_FETCH_SERVERDESC || |
1850 | 0 | conn->base_.purpose == DIR_PURPOSE_FETCH_EXTRAINFO || |
1851 | 0 | conn->base_.purpose == DIR_PURPOSE_FETCH_MICRODESC); |
1852 | |
|
1853 | 0 | int plausible = body_is_plausible(body, body_len, conn->base_.purpose); |
1854 | |
|
1855 | 0 | if (plausible && compression == NO_METHOD) { |
1856 | 0 | return 0; |
1857 | 0 | } |
1858 | | |
1859 | 0 | int severity = LOG_DEBUG; |
1860 | 0 | char *new_body = NULL; |
1861 | 0 | size_t new_len = 0; |
1862 | 0 | const char *description1, *description2; |
1863 | 0 | int want_to_try_both = 0; |
1864 | 0 | int tried_both = 0; |
1865 | 0 | compress_method_t guessed = detect_compression_method(body, body_len); |
1866 | |
|
1867 | 0 | description1 = compression_method_get_human_name(compression); |
1868 | |
|
1869 | 0 | if (BUG(description1 == NULL)) |
1870 | 0 | description1 = compression_method_get_human_name(UNKNOWN_METHOD); |
1871 | |
|
1872 | 0 | if (guessed == UNKNOWN_METHOD && !plausible) |
1873 | 0 | description2 = "confusing binary junk"; |
1874 | 0 | else |
1875 | 0 | description2 = compression_method_get_human_name(guessed); |
1876 | | |
1877 | | /* Tell the user if we don't believe what we're told about compression.*/ |
1878 | 0 | want_to_try_both = (compression == UNKNOWN_METHOD || |
1879 | 0 | guessed != compression); |
1880 | 0 | if (want_to_try_both) { |
1881 | 0 | severity = LOG_PROTOCOL_WARN; |
1882 | 0 | } |
1883 | |
|
1884 | 0 | tor_log(severity, LD_HTTP, |
1885 | 0 | "HTTP body from %s was labeled as %s, " |
1886 | 0 | "%s it seems to be %s.%s", |
1887 | 0 | connection_describe(TO_CONN(conn)), |
1888 | 0 | description1, |
1889 | 0 | guessed != compression?"but":"and", |
1890 | 0 | description2, |
1891 | 0 | (compression>0 && guessed>0 && want_to_try_both)? |
1892 | 0 | " Trying both.":""); |
1893 | | |
1894 | | /* Try declared compression first if we can. |
1895 | | * tor_compress_supports_method() also returns true for NO_METHOD. |
1896 | | * Ensure that the server is not sending us data compressed using a |
1897 | | * compression method that is not allowed for anonymous connections. */ |
1898 | 0 | if (anonymized_connection && |
1899 | 0 | ! allowed_anonymous_connection_compression_method(compression)) { |
1900 | 0 | warn_disallowed_anonymous_compression_method(compression); |
1901 | 0 | rv = -1; |
1902 | 0 | goto done; |
1903 | 0 | } |
1904 | | |
1905 | 0 | if (tor_compress_supports_method(compression)) { |
1906 | 0 | tor_uncompress(&new_body, &new_len, body, body_len, compression, |
1907 | 0 | !allow_partial, LOG_PROTOCOL_WARN); |
1908 | 0 | if (new_body) { |
1909 | | /* We succeeded with the declared compression method. Great! */ |
1910 | 0 | rv = 0; |
1911 | 0 | goto done; |
1912 | 0 | } |
1913 | 0 | } |
1914 | | |
1915 | | /* Okay, if that didn't work, and we think that it was compressed |
1916 | | * differently, try that. */ |
1917 | 0 | if (anonymized_connection && |
1918 | 0 | ! allowed_anonymous_connection_compression_method(guessed)) { |
1919 | 0 | warn_disallowed_anonymous_compression_method(guessed); |
1920 | 0 | rv = -1; |
1921 | 0 | goto done; |
1922 | 0 | } |
1923 | | |
1924 | 0 | if (tor_compress_supports_method(guessed) && |
1925 | 0 | compression != guessed) { |
1926 | 0 | tor_uncompress(&new_body, &new_len, body, body_len, guessed, |
1927 | 0 | !allow_partial, LOG_INFO); |
1928 | 0 | tried_both = 1; |
1929 | 0 | } |
1930 | | /* If we're pretty sure that we have a compressed directory, and |
1931 | | * we didn't manage to uncompress it, then warn and bail. */ |
1932 | 0 | if (!plausible && !new_body) { |
1933 | 0 | static ratelim_t warning_limit = RATELIM_INIT(60 * 60); |
1934 | 0 | log_fn_ratelim(&warning_limit, LOG_WARN, LD_HTTP, |
1935 | 0 | "Unable to decompress HTTP body (tried %s%s%s, on %s).", |
1936 | 0 | description1, |
1937 | 0 | tried_both?" and ":"", |
1938 | 0 | tried_both?description2:"", |
1939 | 0 | connection_describe(TO_CONN(conn))); |
1940 | 0 | rv = -1; |
1941 | 0 | goto done; |
1942 | 0 | } |
1943 | | |
1944 | 0 | done: |
1945 | 0 | if (new_body) { |
1946 | 0 | if (rv == 0) { |
1947 | | /* success! */ |
1948 | 0 | tor_free(*bodyp); |
1949 | 0 | *bodyp = new_body; |
1950 | 0 | *bodylenp = new_len; |
1951 | 0 | } else { |
1952 | 0 | tor_free(new_body); |
1953 | 0 | } |
1954 | 0 | } |
1955 | |
|
1956 | 0 | return rv; |
1957 | 0 | } |
1958 | | |
1959 | | /** |
1960 | | * Total number of bytes downloaded of each directory purpose, when |
1961 | | * bootstrapped, and when not bootstrapped. |
1962 | | * |
1963 | | * (For example, the number of bytes downloaded of purpose p while |
1964 | | * not fully bootstrapped is total_dl[p][false].) |
1965 | | **/ |
1966 | | static uint64_t total_dl[DIR_PURPOSE_MAX_][2]; |
1967 | | |
1968 | | /** |
1969 | | * Heartbeat: dump a summary of how many bytes of which purpose we've |
1970 | | * downloaded, when bootstrapping and when not bootstrapping. |
1971 | | **/ |
1972 | | void |
1973 | | dirclient_dump_total_dls(void) |
1974 | 0 | { |
1975 | 0 | const or_options_t *options = get_options(); |
1976 | 0 | for (int bootstrapped = 0; bootstrapped < 2; ++bootstrapped) { |
1977 | 0 | smartlist_t *lines = smartlist_new(); |
1978 | 0 | for (int i=0; i < DIR_PURPOSE_MAX_; ++i) { |
1979 | 0 | uint64_t n = total_dl[i][bootstrapped]; |
1980 | 0 | if (n == 0) |
1981 | 0 | continue; |
1982 | 0 | if (options->SafeLogging_ != SAFELOG_SCRUB_NONE && |
1983 | 0 | purpose_needs_anonymity(i, ROUTER_PURPOSE_GENERAL, NULL)) |
1984 | 0 | continue; |
1985 | 0 | smartlist_add_asprintf(lines, "%"PRIu64" (%s)", |
1986 | 0 | n, dir_conn_purpose_to_string(i)); |
1987 | 0 | } |
1988 | |
|
1989 | 0 | if (smartlist_len(lines) > 0) { |
1990 | 0 | char *log_line = smartlist_join_strings(lines, "; ", 0, NULL); |
1991 | 0 | log_notice(LD_NET, "While %sbootstrapping, fetched this many bytes: %s", |
1992 | 0 | bootstrapped?"not ":"", log_line); |
1993 | 0 | tor_free(log_line); |
1994 | |
|
1995 | 0 | SMARTLIST_FOREACH(lines, char *, s, tor_free(s)); |
1996 | 0 | } |
1997 | 0 | smartlist_free(lines); |
1998 | 0 | } |
1999 | 0 | } |
2000 | | |
2001 | | /** We are a client, and we've finished reading the server's |
2002 | | * response. Parse it and act appropriately. |
2003 | | * |
2004 | | * If we're still happy with using this directory server in the future, return |
2005 | | * 0. Otherwise return -1; and the caller should consider trying the request |
2006 | | * again. |
2007 | | * |
2008 | | * The caller will take care of marking the connection for close. |
2009 | | */ |
2010 | | static int |
2011 | | connection_dir_client_reached_eof(dir_connection_t *conn) |
2012 | 0 | { |
2013 | 0 | char *body = NULL; |
2014 | 0 | char *headers = NULL; |
2015 | 0 | char *reason = NULL; |
2016 | 0 | size_t body_len = 0; |
2017 | 0 | int status_code; |
2018 | 0 | time_t date_header = 0; |
2019 | 0 | long apparent_skew; |
2020 | 0 | compress_method_t compression; |
2021 | 0 | int skewed = 0; |
2022 | 0 | int rv; |
2023 | 0 | int allow_partial = (conn->base_.purpose == DIR_PURPOSE_FETCH_SERVERDESC || |
2024 | 0 | conn->base_.purpose == DIR_PURPOSE_FETCH_EXTRAINFO || |
2025 | 0 | conn->base_.purpose == DIR_PURPOSE_FETCH_MICRODESC); |
2026 | 0 | size_t received_bytes; |
2027 | 0 | const int anonymized_connection = |
2028 | 0 | purpose_needs_anonymity(conn->base_.purpose, |
2029 | 0 | conn->router_purpose, |
2030 | 0 | conn->requested_resource); |
2031 | |
|
2032 | 0 | received_bytes = connection_get_inbuf_len(TO_CONN(conn)); |
2033 | |
|
2034 | 0 | log_debug(LD_DIR, "Downloaded %"TOR_PRIuSZ" bytes on connection of purpose " |
2035 | 0 | "%s; bootstrap %d%%", |
2036 | 0 | received_bytes, |
2037 | 0 | dir_conn_purpose_to_string(conn->base_.purpose), |
2038 | 0 | control_get_bootstrap_percent()); |
2039 | 0 | { |
2040 | 0 | bool bootstrapped = control_get_bootstrap_percent() == 100; |
2041 | 0 | total_dl[conn->base_.purpose][bootstrapped] += received_bytes; |
2042 | 0 | } |
2043 | |
|
2044 | 0 | switch (connection_fetch_from_buf_http(TO_CONN(conn), |
2045 | 0 | &headers, MAX_HEADERS_SIZE, |
2046 | 0 | &body, &body_len, MAX_DIR_DL_SIZE, |
2047 | 0 | allow_partial)) { |
2048 | 0 | case -1: /* overflow */ |
2049 | 0 | log_warn(LD_PROTOCOL, |
2050 | 0 | "'fetch' response too large (%s). Closing.", |
2051 | 0 | connection_describe(TO_CONN(conn))); |
2052 | 0 | return -1; |
2053 | 0 | case 0: |
2054 | 0 | log_info(LD_HTTP, |
2055 | 0 | "'fetch' response not all here, but we're at eof. Closing."); |
2056 | 0 | return -1; |
2057 | | /* case 1, fall through */ |
2058 | 0 | } |
2059 | | |
2060 | 0 | if (parse_http_response(headers, &status_code, &date_header, |
2061 | 0 | &compression, &reason) < 0) { |
2062 | 0 | log_warn(LD_HTTP,"Unparseable headers (%s). Closing.", |
2063 | 0 | connection_describe(TO_CONN(conn))); |
2064 | 0 | rv = -1; |
2065 | 0 | goto done; |
2066 | 0 | } |
2067 | 0 | if (!reason) reason = tor_strdup("[no reason given]"); |
2068 | |
|
2069 | 0 | tor_log(LOG_DEBUG, LD_DIR, |
2070 | 0 | "Received response on %s: %d %s " |
2071 | 0 | "(purpose: %d, response size: %"TOR_PRIuSZ |
2072 | | #ifdef MEASUREMENTS_21206 |
2073 | | ", data cells received: %d, data cells sent: %d" |
2074 | | #endif |
2075 | 0 | ", compression: %d)", |
2076 | 0 | connection_describe(TO_CONN(conn)), |
2077 | 0 | status_code, |
2078 | 0 | escaped(reason), conn->base_.purpose, |
2079 | 0 | (received_bytes), |
2080 | | #ifdef MEASUREMENTS_21206 |
2081 | | conn->data_cells_received, conn->data_cells_sent, |
2082 | | #endif |
2083 | 0 | compression); |
2084 | |
|
2085 | 0 | if (conn->guard_state) { |
2086 | | /* we count the connection as successful once we can read from it. We do |
2087 | | * not, however, delay use of the circuit here, since it's just for a |
2088 | | * one-hop directory request. */ |
2089 | | /* XXXXprop271 note that this will not do the right thing for other |
2090 | | * waiting circuits that would be triggered by this circuit becoming |
2091 | | * complete/usable. But that's ok, I think. |
2092 | | */ |
2093 | 0 | entry_guard_succeeded(&conn->guard_state); |
2094 | 0 | circuit_guard_state_free(conn->guard_state); |
2095 | 0 | conn->guard_state = NULL; |
2096 | 0 | } |
2097 | | |
2098 | | /* now check if it's got any hints for us about our IP address. */ |
2099 | 0 | if (conn->dirconn_direct) { |
2100 | 0 | char *guess = http_get_header(headers, X_ADDRESS_HEADER); |
2101 | 0 | if (guess) { |
2102 | 0 | tor_addr_t addr; |
2103 | 0 | if (tor_addr_parse(&addr, guess) < 0) { |
2104 | 0 | log_debug(LD_DIR, "Malformed X-Your-Address-Is header %s. Ignoring.", |
2105 | 0 | escaped(guess)); |
2106 | 0 | } else { |
2107 | 0 | relay_address_new_suggestion(&addr, &TO_CONN(conn)->addr, NULL); |
2108 | 0 | } |
2109 | 0 | tor_free(guess); |
2110 | 0 | } |
2111 | 0 | } |
2112 | |
|
2113 | 0 | if (date_header > 0) { |
2114 | | /* The date header was written very soon after we sent our request, |
2115 | | * so compute the skew as the difference between sending the request |
2116 | | * and the date header. (We used to check now-date_header, but that's |
2117 | | * inaccurate if we spend a lot of time downloading.) |
2118 | | */ |
2119 | 0 | apparent_skew = conn->base_.timestamp_last_write_allowed - date_header; |
2120 | 0 | if (labs(apparent_skew)>ALLOW_DIRECTORY_TIME_SKEW) { |
2121 | 0 | int trusted = router_digest_is_trusted_dir(conn->identity_digest); |
2122 | 0 | clock_skew_warning(TO_CONN(conn), apparent_skew, trusted, LD_HTTP, |
2123 | 0 | "directory", "DIRSERV"); |
2124 | 0 | skewed = 1; /* don't check the recommended-versions line */ |
2125 | 0 | } else { |
2126 | 0 | log_debug(LD_HTTP, "Time on received directory is within tolerance; " |
2127 | 0 | "we are %ld seconds skewed. (That's okay.)", apparent_skew); |
2128 | 0 | } |
2129 | 0 | } |
2130 | 0 | (void) skewed; /* skewed isn't used yet. */ |
2131 | |
|
2132 | 0 | if (status_code == 503) { |
2133 | 0 | routerstatus_t *rs; |
2134 | 0 | dir_server_t *ds; |
2135 | 0 | const char *id_digest = conn->identity_digest; |
2136 | 0 | log_info(LD_DIR,"Received http status code %d (%s) from server " |
2137 | 0 | "%s. I'll try again soon.", |
2138 | 0 | status_code, escaped(reason), |
2139 | 0 | connection_describe_peer(TO_CONN(conn))); |
2140 | 0 | time_t now = approx_time(); |
2141 | 0 | if ((rs = router_get_mutable_consensus_status_by_id(id_digest))) |
2142 | 0 | rs->last_dir_503_at = now; |
2143 | 0 | if ((ds = router_get_fallback_dirserver_by_digest(id_digest))) |
2144 | 0 | ds->fake_status.last_dir_503_at = now; |
2145 | |
|
2146 | 0 | rv = -1; |
2147 | 0 | goto done; |
2148 | 0 | } |
2149 | | |
2150 | 0 | if (dir_client_decompress_response_body(&body, &body_len, |
2151 | 0 | conn, compression, anonymized_connection) < 0) { |
2152 | 0 | rv = -1; |
2153 | 0 | goto done; |
2154 | 0 | } |
2155 | | |
2156 | 0 | response_handler_args_t args; |
2157 | 0 | memset(&args, 0, sizeof(args)); |
2158 | 0 | args.status_code = status_code; |
2159 | 0 | args.reason = reason; |
2160 | 0 | args.body = body; |
2161 | 0 | args.body_len = body_len; |
2162 | 0 | args.headers = headers; |
2163 | |
|
2164 | 0 | switch (conn->base_.purpose) { |
2165 | 0 | case DIR_PURPOSE_FETCH_CONSENSUS: |
2166 | 0 | rv = handle_response_fetch_consensus(conn, &args); |
2167 | 0 | break; |
2168 | 0 | case DIR_PURPOSE_FETCH_CERTIFICATE: |
2169 | 0 | rv = handle_response_fetch_certificate(conn, &args); |
2170 | 0 | break; |
2171 | 0 | case DIR_PURPOSE_FETCH_STATUS_VOTE: |
2172 | 0 | rv = handle_response_fetch_status_vote(conn, &args); |
2173 | 0 | break; |
2174 | 0 | case DIR_PURPOSE_FETCH_DETACHED_SIGNATURES: |
2175 | 0 | rv = handle_response_fetch_detached_signatures(conn, &args); |
2176 | 0 | break; |
2177 | 0 | case DIR_PURPOSE_FETCH_SERVERDESC: |
2178 | 0 | case DIR_PURPOSE_FETCH_EXTRAINFO: |
2179 | 0 | rv = handle_response_fetch_desc(conn, &args); |
2180 | 0 | break; |
2181 | 0 | case DIR_PURPOSE_FETCH_MICRODESC: |
2182 | 0 | rv = handle_response_fetch_microdesc(conn, &args); |
2183 | 0 | break; |
2184 | 0 | case DIR_PURPOSE_UPLOAD_DIR: |
2185 | 0 | rv = handle_response_upload_dir(conn, &args); |
2186 | 0 | break; |
2187 | 0 | case DIR_PURPOSE_UPLOAD_SIGNATURES: |
2188 | 0 | rv = handle_response_upload_signatures(conn, &args); |
2189 | 0 | break; |
2190 | 0 | case DIR_PURPOSE_UPLOAD_VOTE: |
2191 | 0 | rv = handle_response_upload_vote(conn, &args); |
2192 | 0 | break; |
2193 | 0 | case DIR_PURPOSE_UPLOAD_HSDESC: |
2194 | 0 | rv = handle_response_upload_hsdesc(conn, &args); |
2195 | 0 | break; |
2196 | 0 | case DIR_PURPOSE_FETCH_HSDESC: |
2197 | 0 | rv = handle_response_fetch_hsdesc_v3(conn, &args); |
2198 | 0 | break; |
2199 | 0 | default: |
2200 | 0 | tor_assert_nonfatal_unreached(); |
2201 | 0 | rv = -1; |
2202 | 0 | break; |
2203 | 0 | } |
2204 | | |
2205 | 0 | done: |
2206 | 0 | tor_free(body); |
2207 | 0 | tor_free(headers); |
2208 | 0 | tor_free(reason); |
2209 | 0 | return rv; |
2210 | 0 | } |
2211 | | |
2212 | | /** |
2213 | | * Handler function: processes a response to a request for a networkstatus |
2214 | | * consensus document by checking the consensus, storing it, and marking |
2215 | | * router requests as reachable. |
2216 | | **/ |
2217 | | STATIC int |
2218 | | handle_response_fetch_consensus(dir_connection_t *conn, |
2219 | | const response_handler_args_t *args) |
2220 | 0 | { |
2221 | 0 | tor_assert(conn->base_.purpose == DIR_PURPOSE_FETCH_CONSENSUS); |
2222 | 0 | const int status_code = args->status_code; |
2223 | 0 | const char *body = args->body; |
2224 | 0 | const size_t body_len = args->body_len; |
2225 | 0 | const char *reason = args->reason; |
2226 | 0 | const time_t now = approx_time(); |
2227 | |
|
2228 | 0 | const char *consensus; |
2229 | 0 | char *new_consensus = NULL; |
2230 | 0 | const char *sourcename; |
2231 | |
|
2232 | 0 | int r; |
2233 | 0 | const char *flavname = conn->requested_resource; |
2234 | 0 | if (status_code != 200) { |
2235 | 0 | int severity = (status_code == 304) ? LOG_INFO : LOG_WARN; |
2236 | 0 | tor_log(severity, LD_DIR, |
2237 | 0 | "Received http status code %d (%s) from server " |
2238 | 0 | "%s while fetching consensus directory.", |
2239 | 0 | status_code, escaped(reason), |
2240 | 0 | connection_describe_peer(TO_CONN(conn))); |
2241 | 0 | networkstatus_consensus_download_failed(status_code, flavname); |
2242 | 0 | return -1; |
2243 | 0 | } |
2244 | | |
2245 | 0 | if (looks_like_a_consensus_diff(body, body_len)) { |
2246 | | /* First find our previous consensus. Maybe it's in ram, maybe not. */ |
2247 | 0 | cached_dir_t *cd = NULL; |
2248 | 0 | const char *consensus_body = NULL; |
2249 | 0 | size_t consensus_body_len; |
2250 | 0 | tor_mmap_t *mapped_consensus = NULL; |
2251 | | |
2252 | | /* We prefer the mmap'd version over the cached_dir_t version, |
2253 | | * since that matches the logic we used when we picked a consensus |
2254 | | * back in dir_consensus_request_set_additional_headers. */ |
2255 | 0 | mapped_consensus = networkstatus_map_cached_consensus(flavname); |
2256 | 0 | if (mapped_consensus) { |
2257 | 0 | consensus_body = mapped_consensus->data; |
2258 | 0 | consensus_body_len = mapped_consensus->size; |
2259 | 0 | } else { |
2260 | 0 | cd = dirserv_get_consensus(flavname); |
2261 | 0 | if (cd) { |
2262 | 0 | consensus_body = cd->dir; |
2263 | 0 | consensus_body_len = cd->dir_len; |
2264 | 0 | } |
2265 | 0 | } |
2266 | 0 | if (!consensus_body) { |
2267 | 0 | log_warn(LD_DIR, "Received a consensus diff, but we can't find " |
2268 | 0 | "any %s-flavored consensus in our current cache.",flavname); |
2269 | 0 | tor_munmap_file(mapped_consensus); |
2270 | 0 | networkstatus_consensus_download_failed(0, flavname); |
2271 | | // XXXX if this happens too much, see below |
2272 | 0 | return -1; |
2273 | 0 | } |
2274 | | |
2275 | 0 | new_consensus = consensus_diff_apply(consensus_body, consensus_body_len, |
2276 | 0 | body, body_len); |
2277 | 0 | tor_munmap_file(mapped_consensus); |
2278 | 0 | if (new_consensus == NULL) { |
2279 | 0 | log_warn(LD_DIR, "Could not apply consensus diff received from server " |
2280 | 0 | "%s", connection_describe_peer(TO_CONN(conn))); |
2281 | | // XXXX If this happens too many times, we should maybe not use |
2282 | | // XXXX this directory for diffs any more? |
2283 | 0 | networkstatus_consensus_download_failed(0, flavname); |
2284 | 0 | return -1; |
2285 | 0 | } |
2286 | 0 | log_info(LD_DIR, "Applied consensus diff (size %d) from server " |
2287 | 0 | "%s, resulting in a new consensus document (size %d).", |
2288 | 0 | (int)body_len, connection_describe_peer(TO_CONN(conn)), |
2289 | 0 | (int)strlen(new_consensus)); |
2290 | 0 | consensus = new_consensus; |
2291 | 0 | sourcename = "generated based on a diff"; |
2292 | 0 | } else { |
2293 | 0 | log_info(LD_DIR,"Received consensus directory (body size %d) from server " |
2294 | 0 | "%s", (int)body_len, connection_describe_peer(TO_CONN(conn))); |
2295 | 0 | consensus = body; |
2296 | 0 | sourcename = "downloaded"; |
2297 | 0 | } |
2298 | | |
2299 | 0 | if ((r=networkstatus_set_current_consensus(consensus, |
2300 | 0 | strlen(consensus), |
2301 | 0 | flavname, 0, |
2302 | 0 | conn->identity_digest))<0) { |
2303 | 0 | log_fn(r<-1?LOG_WARN:LOG_INFO, LD_DIR, |
2304 | 0 | "Unable to load %s consensus directory %s from " |
2305 | 0 | "server %s. I'll try again soon.", |
2306 | 0 | flavname, sourcename, |
2307 | 0 | connection_describe_peer(TO_CONN(conn))); |
2308 | 0 | networkstatus_consensus_download_failed(0, flavname); |
2309 | 0 | tor_free(new_consensus); |
2310 | 0 | return -1; |
2311 | 0 | } |
2312 | | |
2313 | | /* If we launched other fetches for this consensus, cancel them. */ |
2314 | 0 | connection_dir_close_consensus_fetches(conn, flavname); |
2315 | | |
2316 | | /* update the list of routers and directory guards */ |
2317 | 0 | routers_update_all_from_networkstatus(now, 3); |
2318 | 0 | update_microdescs_from_networkstatus(now); |
2319 | 0 | directory_info_has_arrived(now, 0, 0); |
2320 | |
|
2321 | 0 | if (authdir_mode_v3(get_options())) { |
2322 | 0 | sr_act_post_consensus( |
2323 | 0 | networkstatus_get_latest_consensus_by_flavor(FLAV_NS)); |
2324 | 0 | } |
2325 | 0 | log_info(LD_DIR, "Successfully loaded consensus."); |
2326 | |
|
2327 | 0 | tor_free(new_consensus); |
2328 | 0 | return 0; |
2329 | 0 | } |
2330 | | |
2331 | | /** |
2332 | | * Handler function: processes a response to a request for one or more |
2333 | | * authority certificates |
2334 | | **/ |
2335 | | static int |
2336 | | handle_response_fetch_certificate(dir_connection_t *conn, |
2337 | | const response_handler_args_t *args) |
2338 | 0 | { |
2339 | 0 | tor_assert(conn->base_.purpose == DIR_PURPOSE_FETCH_CERTIFICATE); |
2340 | 0 | const int status_code = args->status_code; |
2341 | 0 | const char *reason = args->reason; |
2342 | 0 | const char *body = args->body; |
2343 | 0 | const size_t body_len = args->body_len; |
2344 | |
|
2345 | 0 | if (status_code != 200) { |
2346 | 0 | log_warn(LD_DIR, |
2347 | 0 | "Received http status code %d (%s) from server " |
2348 | 0 | "%s while fetching \"/tor/keys/%s\".", |
2349 | 0 | status_code, escaped(reason), |
2350 | 0 | connection_describe_peer(TO_CONN(conn)), |
2351 | 0 | conn->requested_resource); |
2352 | 0 | connection_dir_download_cert_failed(conn, status_code); |
2353 | 0 | return -1; |
2354 | 0 | } |
2355 | 0 | log_info(LD_DIR,"Received authority certificates (body size %d) from " |
2356 | 0 | "server %s", |
2357 | 0 | (int)body_len, connection_describe_peer(TO_CONN(conn))); |
2358 | | |
2359 | | /* |
2360 | | * Tell trusted_dirs_load_certs_from_string() whether it was by fp |
2361 | | * or fp-sk pair. |
2362 | | */ |
2363 | 0 | int src_code = -1; |
2364 | 0 | if (!strcmpstart(conn->requested_resource, "fp/")) { |
2365 | 0 | src_code = TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_DIGEST; |
2366 | 0 | } else if (!strcmpstart(conn->requested_resource, "fp-sk/")) { |
2367 | 0 | src_code = TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_SK_DIGEST; |
2368 | 0 | } |
2369 | |
|
2370 | 0 | if (src_code != -1) { |
2371 | 0 | if (trusted_dirs_load_certs_from_string(body, src_code, 1, |
2372 | 0 | conn->identity_digest)<0) { |
2373 | 0 | log_warn(LD_DIR, "Unable to parse fetched certificates"); |
2374 | | /* if we fetched more than one and only some failed, the successful |
2375 | | * ones got flushed to disk so it's safe to call this on them */ |
2376 | 0 | connection_dir_download_cert_failed(conn, status_code); |
2377 | 0 | } else { |
2378 | 0 | time_t now = approx_time(); |
2379 | 0 | directory_info_has_arrived(now, 0, 0); |
2380 | 0 | log_info(LD_DIR, "Successfully loaded certificates from fetch."); |
2381 | 0 | } |
2382 | 0 | } else { |
2383 | 0 | log_warn(LD_DIR, |
2384 | 0 | "Couldn't figure out what to do with fetched certificates for " |
2385 | 0 | "unknown resource %s", |
2386 | 0 | conn->requested_resource); |
2387 | 0 | connection_dir_download_cert_failed(conn, status_code); |
2388 | 0 | } |
2389 | 0 | return 0; |
2390 | 0 | } |
2391 | | |
2392 | | /** |
2393 | | * Handler function: processes a response to a request for an authority's |
2394 | | * current networkstatus vote. |
2395 | | **/ |
2396 | | static int |
2397 | | handle_response_fetch_status_vote(dir_connection_t *conn, |
2398 | | const response_handler_args_t *args) |
2399 | 0 | { |
2400 | 0 | tor_assert(conn->base_.purpose == DIR_PURPOSE_FETCH_STATUS_VOTE); |
2401 | 0 | const int status_code = args->status_code; |
2402 | 0 | const char *reason = args->reason; |
2403 | 0 | const char *body = args->body; |
2404 | 0 | const size_t body_len = args->body_len; |
2405 | |
|
2406 | 0 | const char *msg; |
2407 | 0 | int st; |
2408 | 0 | log_notice(LD_DIR,"Got votes (body size %d) from server %s", |
2409 | 0 | (int)body_len, connection_describe_peer(TO_CONN(conn))); |
2410 | 0 | if (status_code != 200) { |
2411 | 0 | log_warn(LD_DIR, |
2412 | 0 | "Received http status code %d (%s) from server " |
2413 | 0 | "%s while fetching \"/tor/status-vote/next/%s.z\".", |
2414 | 0 | status_code, escaped(reason), |
2415 | 0 | connection_describe_peer(TO_CONN(conn)), |
2416 | 0 | conn->requested_resource); |
2417 | 0 | return -1; |
2418 | 0 | } |
2419 | 0 | dirvote_add_vote(body, 0, TO_CONN(conn)->address, &msg, &st); |
2420 | 0 | if (st > 299) { |
2421 | 0 | log_warn(LD_DIR, "Error adding retrieved vote: %s", msg); |
2422 | 0 | } else { |
2423 | 0 | log_info(LD_DIR, "Added vote(s) successfully [msg: %s]", msg); |
2424 | 0 | } |
2425 | |
|
2426 | 0 | return 0; |
2427 | 0 | } |
2428 | | |
2429 | | /** |
2430 | | * Handler function: processes a response to a request for the signatures |
2431 | | * that an authority knows about on a given consensus. |
2432 | | **/ |
2433 | | static int |
2434 | | handle_response_fetch_detached_signatures(dir_connection_t *conn, |
2435 | | const response_handler_args_t *args) |
2436 | 0 | { |
2437 | 0 | tor_assert(conn->base_.purpose == DIR_PURPOSE_FETCH_DETACHED_SIGNATURES); |
2438 | 0 | const int status_code = args->status_code; |
2439 | 0 | const char *reason = args->reason; |
2440 | 0 | const char *body = args->body; |
2441 | 0 | const size_t body_len = args->body_len; |
2442 | |
|
2443 | 0 | const char *msg = NULL; |
2444 | 0 | log_info(LD_DIR,"Got detached signatures (body size %d) from server %s", |
2445 | 0 | (int)body_len, |
2446 | 0 | connection_describe_peer(TO_CONN(conn))); |
2447 | 0 | if (status_code != 200) { |
2448 | 0 | log_warn(LD_DIR, |
2449 | 0 | "Received http status code %d (%s) from server %s while fetching " |
2450 | 0 | "\"/tor/status-vote/next/consensus-signatures.z\".", |
2451 | 0 | status_code, escaped(reason), |
2452 | 0 | connection_describe_peer(TO_CONN(conn))); |
2453 | 0 | return -1; |
2454 | 0 | } |
2455 | 0 | if (dirvote_add_signatures(body, conn->base_.address, &msg)<0) { |
2456 | 0 | log_warn(LD_DIR, "Problem adding detached signatures from %s: %s", |
2457 | 0 | connection_describe_peer(TO_CONN(conn)), |
2458 | 0 | msg?msg:"???"); |
2459 | 0 | } |
2460 | |
|
2461 | 0 | return 0; |
2462 | 0 | } |
2463 | | |
2464 | | /** |
2465 | | * Handler function: processes a response to a request for a group of server |
2466 | | * descriptors or an extrainfo documents. |
2467 | | **/ |
2468 | | static int |
2469 | | handle_response_fetch_desc(dir_connection_t *conn, |
2470 | | const response_handler_args_t *args) |
2471 | 0 | { |
2472 | 0 | tor_assert(conn->base_.purpose == DIR_PURPOSE_FETCH_SERVERDESC || |
2473 | 0 | conn->base_.purpose == DIR_PURPOSE_FETCH_EXTRAINFO); |
2474 | 0 | const int status_code = args->status_code; |
2475 | 0 | const char *reason = args->reason; |
2476 | 0 | const char *body = args->body; |
2477 | 0 | const size_t body_len = args->body_len; |
2478 | |
|
2479 | 0 | int was_ei = conn->base_.purpose == DIR_PURPOSE_FETCH_EXTRAINFO; |
2480 | 0 | smartlist_t *which = NULL; |
2481 | 0 | int n_asked_for = 0; |
2482 | 0 | int descriptor_digests = conn->requested_resource && |
2483 | 0 | !strcmpstart(conn->requested_resource,"d/"); |
2484 | 0 | log_info(LD_DIR,"Received %s (body size %d) from server %s", |
2485 | 0 | was_ei ? "extra server info" : "server info", |
2486 | 0 | (int)body_len, connection_describe_peer(TO_CONN(conn))); |
2487 | 0 | if (conn->requested_resource && |
2488 | 0 | (!strcmpstart(conn->requested_resource,"d/") || |
2489 | 0 | !strcmpstart(conn->requested_resource,"fp/"))) { |
2490 | 0 | which = smartlist_new(); |
2491 | 0 | dir_split_resource_into_fingerprints(conn->requested_resource + |
2492 | 0 | (descriptor_digests ? 2 : 3), |
2493 | 0 | which, NULL, 0); |
2494 | 0 | n_asked_for = smartlist_len(which); |
2495 | 0 | } |
2496 | 0 | if (status_code != 200) { |
2497 | 0 | int dir_okay = status_code == 404 || |
2498 | 0 | (status_code == 400 && !strcmp(reason, "Servers unavailable.")) || |
2499 | 0 | status_code == 301; |
2500 | | /* 404 means that it didn't have them; no big deal. |
2501 | | * Older (pre-0.1.1.8) servers said 400 Servers unavailable instead. |
2502 | | * 301 is considered as an error since Tor does not follow redirects, |
2503 | | * which means we failed to reach the server we wanted. */ |
2504 | 0 | log_fn(dir_okay ? LOG_INFO : LOG_WARN, LD_DIR, |
2505 | 0 | "Received http status code %d (%s) from server %s " |
2506 | 0 | "while fetching \"/tor/server/%s\". I'll try again soon.", |
2507 | 0 | status_code, escaped(reason), |
2508 | 0 | connection_describe_peer(TO_CONN(conn)), |
2509 | 0 | conn->requested_resource); |
2510 | 0 | if (!which) { |
2511 | 0 | connection_dir_download_routerdesc_failed(conn); |
2512 | 0 | } else { |
2513 | 0 | dir_routerdesc_download_failed(which, status_code, |
2514 | 0 | conn->router_purpose, |
2515 | 0 | was_ei, descriptor_digests); |
2516 | 0 | SMARTLIST_FOREACH(which, char *, cp, tor_free(cp)); |
2517 | 0 | smartlist_free(which); |
2518 | 0 | } |
2519 | 0 | return dir_okay ? 0 : -1; |
2520 | 0 | } |
2521 | | /* Learn the routers, assuming we requested by fingerprint or "all" |
2522 | | * or "authority". |
2523 | | * |
2524 | | * We use "authority" to fetch our own descriptor for |
2525 | | * testing, and to fetch bridge descriptors for bootstrapping. Ignore |
2526 | | * the output of "authority" requests unless we are using bridges, |
2527 | | * since otherwise they'll be the response from reachability tests, |
2528 | | * and we don't really want to add that to our routerlist. */ |
2529 | 0 | if (which || (conn->requested_resource && |
2530 | 0 | (!strcmpstart(conn->requested_resource, "all") || |
2531 | 0 | (!strcmpstart(conn->requested_resource, "authority") && |
2532 | 0 | get_options()->UseBridges)))) { |
2533 | | /* as we learn from them, we remove them from 'which' */ |
2534 | 0 | if (was_ei) { |
2535 | 0 | router_load_extrainfo_from_string(body, NULL, SAVED_NOWHERE, which, |
2536 | 0 | descriptor_digests); |
2537 | 0 | } else { |
2538 | | //router_load_routers_from_string(body, NULL, SAVED_NOWHERE, which, |
2539 | | // descriptor_digests, conn->router_purpose); |
2540 | 0 | if (load_downloaded_routers(body, which, descriptor_digests, |
2541 | 0 | conn->router_purpose, |
2542 | 0 | conn->base_.address)) { |
2543 | 0 | time_t now = approx_time(); |
2544 | 0 | directory_info_has_arrived(now, 0, 1); |
2545 | 0 | } |
2546 | 0 | } |
2547 | 0 | } |
2548 | 0 | if (which) { /* mark remaining ones as failed */ |
2549 | 0 | log_info(LD_DIR, "Received %d/%d %s requested from %s", |
2550 | 0 | n_asked_for-smartlist_len(which), n_asked_for, |
2551 | 0 | was_ei ? "extra-info documents" : "router descriptors", |
2552 | 0 | connection_describe_peer(TO_CONN(conn))); |
2553 | 0 | if (smartlist_len(which)) { |
2554 | 0 | dir_routerdesc_download_failed(which, status_code, |
2555 | 0 | conn->router_purpose, |
2556 | 0 | was_ei, descriptor_digests); |
2557 | 0 | } |
2558 | 0 | SMARTLIST_FOREACH(which, char *, cp, tor_free(cp)); |
2559 | 0 | smartlist_free(which); |
2560 | 0 | } |
2561 | |
|
2562 | 0 | return 0; |
2563 | 0 | } |
2564 | | |
2565 | | /** |
2566 | | * Handler function: processes a response to a request for a group of |
2567 | | * microdescriptors |
2568 | | **/ |
2569 | | STATIC int |
2570 | | handle_response_fetch_microdesc(dir_connection_t *conn, |
2571 | | const response_handler_args_t *args) |
2572 | 0 | { |
2573 | 0 | tor_assert(conn->base_.purpose == DIR_PURPOSE_FETCH_MICRODESC); |
2574 | 0 | const int status_code = args->status_code; |
2575 | 0 | const char *reason = args->reason; |
2576 | 0 | const char *body = args->body; |
2577 | 0 | const size_t body_len = args->body_len; |
2578 | |
|
2579 | 0 | smartlist_t *which = NULL; |
2580 | 0 | log_info(LD_DIR,"Received answer to microdescriptor request (status %d, " |
2581 | 0 | "body size %d) from server %s", |
2582 | 0 | status_code, (int)body_len, |
2583 | 0 | connection_describe_peer(TO_CONN(conn))); |
2584 | 0 | tor_assert(conn->requested_resource && |
2585 | 0 | !strcmpstart(conn->requested_resource, "d/")); |
2586 | 0 | tor_assert_nonfatal(!fast_mem_is_zero(conn->identity_digest, DIGEST_LEN)); |
2587 | 0 | which = smartlist_new(); |
2588 | 0 | dir_split_resource_into_fingerprints(conn->requested_resource+2, |
2589 | 0 | which, NULL, |
2590 | 0 | DSR_DIGEST256|DSR_BASE64); |
2591 | 0 | if (status_code != 200) { |
2592 | 0 | log_info(LD_DIR, "Received status code %d (%s) from server " |
2593 | 0 | "%s while fetching \"/tor/micro/%s\". I'll try again " |
2594 | 0 | "soon.", |
2595 | 0 | status_code, escaped(reason), |
2596 | 0 | connection_describe_peer(TO_CONN(conn)), |
2597 | 0 | conn->requested_resource); |
2598 | 0 | dir_microdesc_download_failed(which, status_code, conn->identity_digest); |
2599 | 0 | SMARTLIST_FOREACH(which, char *, cp, tor_free(cp)); |
2600 | 0 | smartlist_free(which); |
2601 | 0 | return 0; |
2602 | 0 | } else { |
2603 | 0 | smartlist_t *mds; |
2604 | 0 | time_t now = approx_time(); |
2605 | 0 | mds = microdescs_add_to_cache(get_microdesc_cache(), |
2606 | 0 | body, body+body_len, SAVED_NOWHERE, 0, |
2607 | 0 | now, which); |
2608 | 0 | if (smartlist_len(which)) { |
2609 | | /* Mark remaining ones as failed. */ |
2610 | 0 | dir_microdesc_download_failed(which, status_code, conn->identity_digest); |
2611 | 0 | } |
2612 | 0 | if (mds && smartlist_len(mds)) { |
2613 | 0 | control_event_boot_dir(BOOTSTRAP_STATUS_LOADING_DESCRIPTORS, |
2614 | 0 | count_loading_descriptors_progress()); |
2615 | 0 | directory_info_has_arrived(now, 0, 1); |
2616 | 0 | } |
2617 | 0 | SMARTLIST_FOREACH(which, char *, cp, tor_free(cp)); |
2618 | 0 | smartlist_free(which); |
2619 | 0 | smartlist_free(mds); |
2620 | 0 | } |
2621 | | |
2622 | 0 | return 0; |
2623 | 0 | } |
2624 | | |
2625 | | /** |
2626 | | * Handler function: processes a response to a POST request to upload our |
2627 | | * router descriptor. |
2628 | | **/ |
2629 | | static int |
2630 | | handle_response_upload_dir(dir_connection_t *conn, |
2631 | | const response_handler_args_t *args) |
2632 | 0 | { |
2633 | 0 | tor_assert(conn->base_.purpose == DIR_PURPOSE_UPLOAD_DIR); |
2634 | 0 | const int status_code = args->status_code; |
2635 | 0 | const char *reason = args->reason; |
2636 | 0 | const char *headers = args->headers; |
2637 | |
|
2638 | 0 | switch (status_code) { |
2639 | 0 | case 200: { |
2640 | 0 | dir_server_t *ds = |
2641 | 0 | router_get_trusteddirserver_by_digest(conn->identity_digest); |
2642 | 0 | char *rejected_hdr = http_get_header(headers, |
2643 | 0 | "X-Descriptor-Not-New: "); |
2644 | 0 | if (rejected_hdr) { |
2645 | 0 | if (!strcmp(rejected_hdr, "Yes")) { |
2646 | 0 | log_info(LD_GENERAL, |
2647 | 0 | "Authority '%s' declined our descriptor (not new)", |
2648 | 0 | ds->nickname); |
2649 | | /* XXXX use this information; be sure to upload next one |
2650 | | * sooner. -NM */ |
2651 | | /* XXXX++ On further thought, the task above implies that we're |
2652 | | * basing our regenerate-descriptor time on when we uploaded the |
2653 | | * last descriptor, not on the published time of the last |
2654 | | * descriptor. If those are different, that's a bad thing to |
2655 | | * do. -NM */ |
2656 | 0 | } |
2657 | 0 | tor_free(rejected_hdr); |
2658 | 0 | } |
2659 | 0 | log_info(LD_GENERAL,"eof (status 200) after uploading server " |
2660 | 0 | "descriptor: finished."); |
2661 | 0 | control_event_server_status( |
2662 | 0 | LOG_NOTICE, "ACCEPTED_SERVER_DESCRIPTOR DIRAUTH=%s:%d", |
2663 | 0 | conn->base_.address, conn->base_.port); |
2664 | |
|
2665 | 0 | ds->has_accepted_serverdesc = 1; |
2666 | 0 | if (directories_have_accepted_server_descriptor()) |
2667 | 0 | control_event_server_status(LOG_NOTICE, "GOOD_SERVER_DESCRIPTOR"); |
2668 | 0 | } |
2669 | 0 | break; |
2670 | 0 | case 400: |
2671 | 0 | log_warn(LD_GENERAL,"http status 400 (%s) response from " |
2672 | 0 | "dirserver %s. Please correct.", |
2673 | 0 | escaped(reason), connection_describe_peer(TO_CONN(conn))); |
2674 | 0 | control_event_server_status(LOG_WARN, |
2675 | 0 | "BAD_SERVER_DESCRIPTOR DIRAUTH=%s:%d REASON=\"%s\"", |
2676 | 0 | conn->base_.address, conn->base_.port, escaped(reason)); |
2677 | 0 | break; |
2678 | 0 | default: |
2679 | 0 | log_warn(LD_GENERAL, |
2680 | 0 | "HTTP status %d (%s) was unexpected while uploading " |
2681 | 0 | "descriptor to server %s'. Possibly the server is " |
2682 | 0 | "misconfigured?", |
2683 | 0 | status_code, escaped(reason), |
2684 | 0 | connection_describe_peer(TO_CONN(conn))); |
2685 | 0 | break; |
2686 | 0 | } |
2687 | | /* return 0 in all cases, since we don't want to mark any |
2688 | | * dirservers down just because they don't like us. */ |
2689 | | |
2690 | 0 | return 0; |
2691 | 0 | } |
2692 | | |
2693 | | /** |
2694 | | * Handler function: processes a response to POST request to upload our |
2695 | | * own networkstatus vote. |
2696 | | **/ |
2697 | | static int |
2698 | | handle_response_upload_vote(dir_connection_t *conn, |
2699 | | const response_handler_args_t *args) |
2700 | 0 | { |
2701 | 0 | tor_assert(conn->base_.purpose == DIR_PURPOSE_UPLOAD_VOTE); |
2702 | 0 | const int status_code = args->status_code; |
2703 | 0 | const char *reason = args->reason; |
2704 | |
|
2705 | 0 | switch (status_code) { |
2706 | 0 | case 200: { |
2707 | 0 | log_notice(LD_DIR,"Uploaded my vote to dirserver %s", |
2708 | 0 | connection_describe_peer(TO_CONN(conn))); |
2709 | 0 | } |
2710 | 0 | break; |
2711 | 0 | case 400: |
2712 | 0 | log_warn(LD_DIR,"http status 400 (%s) response after uploading " |
2713 | 0 | "vote to dirserver %s. Please correct.", |
2714 | 0 | escaped(reason), connection_describe_peer(TO_CONN(conn))); |
2715 | 0 | break; |
2716 | 0 | default: |
2717 | 0 | log_warn(LD_GENERAL, |
2718 | 0 | "HTTP status %d (%s) was unexpected while uploading " |
2719 | 0 | "vote to server %s.", |
2720 | 0 | status_code, escaped(reason), |
2721 | 0 | connection_describe_peer(TO_CONN(conn))); |
2722 | 0 | break; |
2723 | 0 | } |
2724 | | /* return 0 in all cases, since we don't want to mark any |
2725 | | * dirservers down just because they don't like us. */ |
2726 | 0 | return 0; |
2727 | 0 | } |
2728 | | |
2729 | | /** |
2730 | | * Handler function: processes a response to POST request to upload our |
2731 | | * view of the signatures on the current consensus. |
2732 | | **/ |
2733 | | static int |
2734 | | handle_response_upload_signatures(dir_connection_t *conn, |
2735 | | const response_handler_args_t *args) |
2736 | 0 | { |
2737 | 0 | tor_assert(conn->base_.purpose == DIR_PURPOSE_UPLOAD_SIGNATURES); |
2738 | 0 | const int status_code = args->status_code; |
2739 | 0 | const char *reason = args->reason; |
2740 | |
|
2741 | 0 | switch (status_code) { |
2742 | 0 | case 200: { |
2743 | 0 | log_notice(LD_DIR,"Uploaded signature(s) to dirserver %s", |
2744 | 0 | connection_describe_peer(TO_CONN(conn))); |
2745 | 0 | } |
2746 | 0 | break; |
2747 | 0 | case 400: |
2748 | 0 | log_warn(LD_DIR,"http status 400 (%s) response after uploading " |
2749 | 0 | "signatures to dirserver %s. Please correct.", |
2750 | 0 | escaped(reason), connection_describe_peer(TO_CONN(conn))); |
2751 | 0 | break; |
2752 | 0 | default: |
2753 | 0 | log_warn(LD_GENERAL, |
2754 | 0 | "HTTP status %d (%s) was unexpected while uploading " |
2755 | 0 | "signatures to server %s.", |
2756 | 0 | status_code, escaped(reason), |
2757 | 0 | connection_describe_peer(TO_CONN(conn))); |
2758 | 0 | break; |
2759 | 0 | } |
2760 | | /* return 0 in all cases, since we don't want to mark any |
2761 | | * dirservers down just because they don't like us. */ |
2762 | | |
2763 | 0 | return 0; |
2764 | 0 | } |
2765 | | |
2766 | | /** |
2767 | | * Handler function: processes a response to a request for a v3 hidden service |
2768 | | * descriptor. |
2769 | | **/ |
2770 | | STATIC int |
2771 | | handle_response_fetch_hsdesc_v3(dir_connection_t *conn, |
2772 | | const response_handler_args_t *args) |
2773 | 0 | { |
2774 | 0 | const int status_code = args->status_code; |
2775 | 0 | const char *reason = args->reason; |
2776 | 0 | const char *body = args->body; |
2777 | 0 | const size_t body_len = args->body_len; |
2778 | |
|
2779 | 0 | tor_assert(conn->hs_ident); |
2780 | |
|
2781 | 0 | log_info(LD_REND,"Received v3 hsdesc (body size %d, status %d (%s))", |
2782 | 0 | (int)body_len, status_code, escaped(reason)); |
2783 | |
|
2784 | 0 | hs_client_dir_fetch_done(conn, reason, body, status_code); |
2785 | 0 | return 0; |
2786 | 0 | } |
2787 | | |
2788 | | /** |
2789 | | * Handler function: processes a response to a POST request to upload an |
2790 | | * hidden service descriptor. |
2791 | | **/ |
2792 | | static int |
2793 | | handle_response_upload_hsdesc(dir_connection_t *conn, |
2794 | | const response_handler_args_t *args) |
2795 | 0 | { |
2796 | 0 | const int status_code = args->status_code; |
2797 | 0 | const char *reason = args->reason; |
2798 | |
|
2799 | 0 | tor_assert(conn); |
2800 | 0 | tor_assert(conn->base_.purpose == DIR_PURPOSE_UPLOAD_HSDESC); |
2801 | |
|
2802 | 0 | log_info(LD_REND, "Uploaded hidden service descriptor (status %d " |
2803 | 0 | "(%s))", |
2804 | 0 | status_code, escaped(reason)); |
2805 | | /* For this directory response, it MUST have an hidden service identifier on |
2806 | | * this connection. */ |
2807 | 0 | tor_assert(conn->hs_ident); |
2808 | 0 | switch (status_code) { |
2809 | 0 | case 200: |
2810 | 0 | log_info(LD_REND, "Uploading hidden service descriptor: " |
2811 | 0 | "finished with status 200 (%s)", escaped(reason)); |
2812 | 0 | hs_control_desc_event_uploaded(conn->hs_ident, conn->identity_digest); |
2813 | 0 | break; |
2814 | 0 | case 400: |
2815 | 0 | log_fn(LOG_PROTOCOL_WARN, LD_REND, |
2816 | 0 | "Uploading hidden service descriptor: http " |
2817 | 0 | "status 400 (%s) response from dirserver " |
2818 | 0 | "%s. Malformed hidden service descriptor?", |
2819 | 0 | escaped(reason), connection_describe_peer(TO_CONN(conn))); |
2820 | 0 | hs_control_desc_event_failed(conn->hs_ident, conn->identity_digest, |
2821 | 0 | "UPLOAD_REJECTED"); |
2822 | 0 | break; |
2823 | 0 | default: |
2824 | 0 | log_warn(LD_REND, "Uploading hidden service descriptor: http " |
2825 | 0 | "status %d (%s) response unexpected (server " |
2826 | 0 | "%s').", |
2827 | 0 | status_code, escaped(reason), |
2828 | 0 | connection_describe_peer(TO_CONN(conn))); |
2829 | 0 | hs_control_desc_event_failed(conn->hs_ident, conn->identity_digest, |
2830 | 0 | "UNEXPECTED"); |
2831 | 0 | break; |
2832 | 0 | } |
2833 | | |
2834 | 0 | return 0; |
2835 | 0 | } |
2836 | | |
2837 | | /** Called when a directory connection reaches EOF. */ |
2838 | | int |
2839 | | connection_dir_reached_eof(dir_connection_t *conn) |
2840 | 0 | { |
2841 | 0 | int retval; |
2842 | 0 | if (conn->base_.state != DIR_CONN_STATE_CLIENT_READING) { |
2843 | 0 | log_info(LD_HTTP,"conn reached eof, not reading. [state=%d] Closing.", |
2844 | 0 | conn->base_.state); |
2845 | 0 | connection_close_immediate(TO_CONN(conn)); /* error: give up on flushing */ |
2846 | 0 | connection_mark_for_close(TO_CONN(conn)); |
2847 | 0 | return -1; |
2848 | 0 | } |
2849 | | |
2850 | 0 | retval = connection_dir_client_reached_eof(conn); |
2851 | 0 | if (retval == 0) /* success */ |
2852 | 0 | conn->base_.state = DIR_CONN_STATE_CLIENT_FINISHED; |
2853 | 0 | connection_mark_for_close(TO_CONN(conn)); |
2854 | 0 | return retval; |
2855 | 0 | } |
2856 | | /** We are closing a dir connection: If <b>dir_conn</b> is a dir connection |
2857 | | * that tried to fetch an HS descriptor, check if it successfully fetched it, |
2858 | | * or if we need to try again. */ |
2859 | | void |
2860 | | connection_dir_client_refetch_hsdesc_if_needed(dir_connection_t *dir_conn) |
2861 | 0 | { |
2862 | 0 | connection_t *conn = TO_CONN(dir_conn); |
2863 | | |
2864 | | /* Check for v3 rend desc fetch */ |
2865 | 0 | if (conn->purpose == DIR_PURPOSE_FETCH_HSDESC && |
2866 | 0 | dir_conn->hs_ident && |
2867 | 0 | !ed25519_public_key_is_zero(&dir_conn->hs_ident->identity_pk)) { |
2868 | 0 | hs_client_refetch_hsdesc(&dir_conn->hs_ident->identity_pk); |
2869 | 0 | } |
2870 | 0 | } |
2871 | | |
2872 | | /** Array of compression methods to use (if supported) for requesting |
2873 | | * compressed data, ordered from best to worst. */ |
2874 | | static compress_method_t client_meth_pref[] = { |
2875 | | LZMA_METHOD, |
2876 | | ZSTD_METHOD, |
2877 | | ZLIB_METHOD, |
2878 | | GZIP_METHOD, |
2879 | | NO_METHOD |
2880 | | }; |
2881 | | |
2882 | | /** Array of allowed compression methods to use (if supported) when receiving a |
2883 | | * response from a request that was required to be anonymous. */ |
2884 | | static compress_method_t client_meth_allowed_anonymous_compression[] = { |
2885 | | ZLIB_METHOD, |
2886 | | GZIP_METHOD, |
2887 | | NO_METHOD |
2888 | | }; |
2889 | | |
2890 | | /** Return a newly allocated string containing a comma separated list of |
2891 | | * supported encodings. */ |
2892 | | STATIC char * |
2893 | | accept_encoding_header(void) |
2894 | 0 | { |
2895 | 0 | smartlist_t *methods = smartlist_new(); |
2896 | 0 | char *header = NULL; |
2897 | 0 | compress_method_t method; |
2898 | 0 | unsigned i; |
2899 | |
|
2900 | 0 | for (i = 0; i < ARRAY_LENGTH(client_meth_pref); ++i) { |
2901 | 0 | method = client_meth_pref[i]; |
2902 | 0 | if (tor_compress_supports_method(method)) |
2903 | 0 | smartlist_add(methods, (char *)compression_method_get_name(method)); |
2904 | 0 | } |
2905 | |
|
2906 | 0 | header = smartlist_join_strings(methods, ", ", 0, NULL); |
2907 | 0 | smartlist_free(methods); |
2908 | |
|
2909 | 0 | return header; |
2910 | 0 | } |
2911 | | |
2912 | | /** Check if the given compression method is allowed for a connection that is |
2913 | | * supposed to be anonymous. Returns 1 if the compression method is allowed, |
2914 | | * otherwise 0. */ |
2915 | | STATIC int |
2916 | | allowed_anonymous_connection_compression_method(compress_method_t method) |
2917 | 0 | { |
2918 | 0 | unsigned u; |
2919 | |
|
2920 | 0 | for (u = 0; u < ARRAY_LENGTH(client_meth_allowed_anonymous_compression); |
2921 | 0 | ++u) { |
2922 | 0 | compress_method_t allowed_method = |
2923 | 0 | client_meth_allowed_anonymous_compression[u]; |
2924 | |
|
2925 | 0 | if (! tor_compress_supports_method(allowed_method)) |
2926 | 0 | continue; |
2927 | | |
2928 | 0 | if (method == allowed_method) |
2929 | 0 | return 1; |
2930 | 0 | } |
2931 | | |
2932 | 0 | return 0; |
2933 | 0 | } |
2934 | | |
2935 | | /** Log a warning when a remote server has sent us a document using a |
2936 | | * compression method that is not allowed for anonymous directory requests. */ |
2937 | | STATIC void |
2938 | | warn_disallowed_anonymous_compression_method(compress_method_t method) |
2939 | 0 | { |
2940 | 0 | log_fn(LOG_PROTOCOL_WARN, LD_HTTP, |
2941 | 0 | "Received a %s HTTP response, which is not " |
2942 | 0 | "allowed for anonymous directory requests.", |
2943 | 0 | compression_method_get_human_name(method)); |
2944 | 0 | } |
2945 | | |
2946 | | /* We just got a new consensus! If there are other in-progress requests |
2947 | | * for this consensus flavor (for example because we launched several in |
2948 | | * parallel), cancel them. |
2949 | | * |
2950 | | * We do this check here (not just in |
2951 | | * connection_ap_handshake_attach_circuit()) to handle the edge case where |
2952 | | * a consensus fetch begins and ends before some other one tries to attach to |
2953 | | * a circuit, in which case the other one won't know that we're all happy now. |
2954 | | * |
2955 | | * Don't mark the conn that just gave us the consensus -- otherwise we |
2956 | | * would end up double-marking it when it cleans itself up. |
2957 | | */ |
2958 | | static void |
2959 | | connection_dir_close_consensus_fetches(dir_connection_t *except_this_one, |
2960 | | const char *resource) |
2961 | 0 | { |
2962 | 0 | smartlist_t *conns_to_close = |
2963 | 0 | connection_dir_list_by_purpose_and_resource(DIR_PURPOSE_FETCH_CONSENSUS, |
2964 | 0 | resource); |
2965 | 0 | SMARTLIST_FOREACH_BEGIN(conns_to_close, dir_connection_t *, d) { |
2966 | 0 | if (d == except_this_one) |
2967 | 0 | continue; |
2968 | 0 | log_info(LD_DIR, "Closing consensus fetch (to %s) since one " |
2969 | 0 | "has just arrived.", connection_describe_peer(TO_CONN(d))); |
2970 | 0 | connection_mark_for_close(TO_CONN(d)); |
2971 | 0 | } SMARTLIST_FOREACH_END(d); |
2972 | 0 | smartlist_free(conns_to_close); |
2973 | 0 | } |
2974 | | /** Called when one or more routerdesc (or extrainfo, if <b>was_extrainfo</b>) |
2975 | | * fetches have failed (with uppercase fingerprints listed in <b>failed</b>, |
2976 | | * either as descriptor digests or as identity digests based on |
2977 | | * <b>was_descriptor_digests</b>). |
2978 | | */ |
2979 | | static void |
2980 | | dir_routerdesc_download_failed(smartlist_t *failed, int status_code, |
2981 | | int router_purpose, |
2982 | | int was_extrainfo, int was_descriptor_digests) |
2983 | 0 | { |
2984 | 0 | char digest[DIGEST_LEN]; |
2985 | 0 | time_t now = time(NULL); |
2986 | 0 | int server = dirclient_fetches_from_authorities(get_options()); |
2987 | 0 | if (!was_descriptor_digests) { |
2988 | 0 | if (router_purpose == ROUTER_PURPOSE_BRIDGE) { |
2989 | 0 | tor_assert(!was_extrainfo); |
2990 | 0 | connection_dir_retry_bridges(failed); |
2991 | 0 | } |
2992 | 0 | return; /* FFFF should implement for other-than-router-purpose someday */ |
2993 | 0 | } |
2994 | 0 | SMARTLIST_FOREACH_BEGIN(failed, const char *, cp) { |
2995 | 0 | download_status_t *dls = NULL; |
2996 | 0 | if (base16_decode(digest, DIGEST_LEN, cp, strlen(cp)) != DIGEST_LEN) { |
2997 | 0 | log_warn(LD_BUG, "Malformed fingerprint in list: %s", escaped(cp)); |
2998 | 0 | continue; |
2999 | 0 | } |
3000 | 0 | if (was_extrainfo) { |
3001 | 0 | signed_descriptor_t *sd = |
3002 | 0 | router_get_by_extrainfo_digest(digest); |
3003 | 0 | if (sd) |
3004 | 0 | dls = &sd->ei_dl_status; |
3005 | 0 | } else { |
3006 | 0 | dls = router_get_dl_status_by_descriptor_digest(digest); |
3007 | 0 | } |
3008 | 0 | if (!dls) |
3009 | 0 | continue; |
3010 | 0 | download_status_increment_failure(dls, status_code, cp, server, now); |
3011 | 0 | } SMARTLIST_FOREACH_END(cp); |
3012 | | |
3013 | | /* No need to relaunch descriptor downloads here: we already do it |
3014 | | * every 10 or 60 seconds (FOO_DESCRIPTOR_RETRY_INTERVAL) in main.c. */ |
3015 | 0 | } |
3016 | | |
3017 | | /** Called when a connection to download microdescriptors from relay with |
3018 | | * <b>dir_id</b> has failed in whole or in part. <b>failed</b> is a list |
3019 | | * of every microdesc digest we didn't get. <b>status_code</b> is the http |
3020 | | * status code we received. Reschedule the microdesc downloads as |
3021 | | * appropriate. */ |
3022 | | static void |
3023 | | dir_microdesc_download_failed(smartlist_t *failed, |
3024 | | int status_code, const char *dir_id) |
3025 | 0 | { |
3026 | 0 | networkstatus_t *consensus |
3027 | 0 | = networkstatus_get_latest_consensus_by_flavor(FLAV_MICRODESC); |
3028 | 0 | routerstatus_t *rs; |
3029 | 0 | download_status_t *dls; |
3030 | 0 | time_t now = time(NULL); |
3031 | 0 | int server = dirclient_fetches_from_authorities(get_options()); |
3032 | |
|
3033 | 0 | if (! consensus) |
3034 | 0 | return; |
3035 | | |
3036 | | /* We failed to fetch a microdescriptor from 'dir_id', note it down |
3037 | | * so that we don't try the same relay next time... */ |
3038 | 0 | microdesc_note_outdated_dirserver(dir_id); |
3039 | |
|
3040 | 0 | SMARTLIST_FOREACH_BEGIN(failed, const char *, d) { |
3041 | 0 | rs = router_get_mutable_consensus_status_by_descriptor_digest(consensus,d); |
3042 | 0 | if (!rs) |
3043 | 0 | continue; |
3044 | 0 | dls = &rs->dl_status; |
3045 | |
|
3046 | 0 | { /* Increment the failure count for this md fetch */ |
3047 | 0 | char buf[BASE64_DIGEST256_LEN+1]; |
3048 | 0 | digest256_to_base64(buf, d); |
3049 | 0 | log_info(LD_DIR, "Failed to download md %s from %s", |
3050 | 0 | buf, hex_str(dir_id, DIGEST_LEN)); |
3051 | 0 | download_status_increment_failure(dls, status_code, buf, |
3052 | 0 | server, now); |
3053 | 0 | } |
3054 | | } SMARTLIST_FOREACH_END(d); |
3055 | 0 | } |