rip out hid_serv_acting_as_directory()
[tor.git] / src / or / directory.c
blob961e33424b254d2a90defc0a1af45449e9bf27b1
1 /* Copyright (c) 2001-2004, Roger Dingledine.
2 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
3 * Copyright (c) 2007-2016, The Tor Project, Inc. */
4 /* See LICENSE for licensing information */
6 #include "or.h"
7 #include "backtrace.h"
8 #include "buffers.h"
9 #include "circuitbuild.h"
10 #include "config.h"
11 #include "connection.h"
12 #include "connection_edge.h"
13 #include "control.h"
14 #include "directory.h"
15 #include "dirserv.h"
16 #include "dirvote.h"
17 #include "entrynodes.h"
18 #include "geoip.h"
19 #include "main.h"
20 #include "microdesc.h"
21 #include "networkstatus.h"
22 #include "nodelist.h"
23 #include "policies.h"
24 #include "relay.h"
25 #include "rendclient.h"
26 #include "rendcommon.h"
27 #include "rendservice.h"
28 #include "rephist.h"
29 #include "router.h"
30 #include "routerlist.h"
31 #include "routerparse.h"
32 #include "routerset.h"
34 #if defined(EXPORTMALLINFO) && defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO)
35 #ifndef OPENBSD
36 #include <malloc.h>
37 #endif
38 #endif
40 /**
41 * \file directory.c
42 * \brief Code to send and fetch directories and router
43 * descriptors via HTTP. Directories use dirserv.c to generate the
44 * results; clients use routers.c to parse them.
45 **/
47 /* In-points to directory.c:
49 * - directory_post_to_dirservers(), called from
50 * router_upload_dir_desc_to_dirservers() in router.c
51 * upload_service_descriptor() in rendservice.c
52 * - directory_get_from_dirserver(), called from
53 * rend_client_refetch_renddesc() in rendclient.c
54 * run_scheduled_events() in main.c
55 * do_hup() in main.c
56 * - connection_dir_process_inbuf(), called from
57 * connection_process_inbuf() in connection.c
58 * - connection_dir_finished_flushing(), called from
59 * connection_finished_flushing() in connection.c
60 * - connection_dir_finished_connecting(), called from
61 * connection_finished_connecting() in connection.c
63 static void directory_send_command(dir_connection_t *conn,
64 int purpose, int direct, const char *resource,
65 const char *payload, size_t payload_len,
66 time_t if_modified_since);
67 static int directory_handle_command(dir_connection_t *conn);
68 static int body_is_plausible(const char *body, size_t body_len, int purpose);
69 static char *http_get_header(const char *headers, const char *which);
70 static void http_set_address_origin(const char *headers, connection_t *conn);
71 static void connection_dir_download_routerdesc_failed(dir_connection_t *conn);
72 static void connection_dir_bridge_routerdesc_failed(dir_connection_t *conn);
73 static void connection_dir_download_cert_failed(
74 dir_connection_t *conn, int status_code);
75 static void connection_dir_retry_bridges(smartlist_t *descs);
76 static void dir_routerdesc_download_failed(smartlist_t *failed,
77 int status_code,
78 int router_purpose,
79 int was_extrainfo,
80 int was_descriptor_digests);
81 static void dir_microdesc_download_failed(smartlist_t *failed,
82 int status_code);
83 static void note_client_request(int purpose, int compressed, size_t bytes);
84 static int client_likes_consensus(networkstatus_t *v, const char *want_url);
86 static void directory_initiate_command_rend(
87 const tor_addr_port_t *or_addr_port,
88 const tor_addr_port_t *dir_addr_port,
89 const char *digest,
90 uint8_t dir_purpose,
91 uint8_t router_purpose,
92 dir_indirection_t indirection,
93 const char *resource,
94 const char *payload,
95 size_t payload_len,
96 time_t if_modified_since,
97 const rend_data_t *rend_query);
99 /********* START VARIABLES **********/
101 /** How far in the future do we allow a directory server to tell us it is
102 * before deciding that one of us has the wrong time? */
103 #define ALLOW_DIRECTORY_TIME_SKEW (30*60)
105 #define X_ADDRESS_HEADER "X-Your-Address-Is: "
107 /** HTTP cache control: how long do we tell proxies they can cache each
108 * kind of document we serve? */
109 #define FULL_DIR_CACHE_LIFETIME (60*60)
110 #define RUNNINGROUTERS_CACHE_LIFETIME (20*60)
111 #define DIRPORTFRONTPAGE_CACHE_LIFETIME (20*60)
112 #define NETWORKSTATUS_CACHE_LIFETIME (5*60)
113 #define ROUTERDESC_CACHE_LIFETIME (30*60)
114 #define ROUTERDESC_BY_DIGEST_CACHE_LIFETIME (48*60*60)
115 #define ROBOTS_CACHE_LIFETIME (24*60*60)
116 #define MICRODESC_CACHE_LIFETIME (48*60*60)
118 /********* END VARIABLES ************/
120 /** Return true iff the directory purpose <b>dir_purpose</b> (and if it's
121 * fetching descriptors, it's fetching them for <b>router_purpose</b>)
122 * must use an anonymous connection to a directory. */
123 STATIC int
124 purpose_needs_anonymity(uint8_t dir_purpose, uint8_t router_purpose)
126 if (get_options()->AllDirActionsPrivate)
127 return 1;
128 if (router_purpose == ROUTER_PURPOSE_BRIDGE)
129 return 1; /* if no circuits yet, this might break bootstrapping, but it's
130 * needed to be safe. */
131 if (dir_purpose == DIR_PURPOSE_UPLOAD_DIR ||
132 dir_purpose == DIR_PURPOSE_UPLOAD_VOTE ||
133 dir_purpose == DIR_PURPOSE_UPLOAD_SIGNATURES ||
134 dir_purpose == DIR_PURPOSE_FETCH_STATUS_VOTE ||
135 dir_purpose == DIR_PURPOSE_FETCH_DETACHED_SIGNATURES ||
136 dir_purpose == DIR_PURPOSE_FETCH_CONSENSUS ||
137 dir_purpose == DIR_PURPOSE_FETCH_CERTIFICATE ||
138 dir_purpose == DIR_PURPOSE_FETCH_SERVERDESC ||
139 dir_purpose == DIR_PURPOSE_FETCH_EXTRAINFO ||
140 dir_purpose == DIR_PURPOSE_FETCH_MICRODESC)
141 return 0;
142 return 1;
145 /** Return a newly allocated string describing <b>auth</b>. Only describes
146 * authority features. */
147 STATIC char *
148 authdir_type_to_string(dirinfo_type_t auth)
150 char *result;
151 smartlist_t *lst = smartlist_new();
152 if (auth & V3_DIRINFO)
153 smartlist_add(lst, (void*)"V3");
154 if (auth & BRIDGE_DIRINFO)
155 smartlist_add(lst, (void*)"Bridge");
156 if (smartlist_len(lst)) {
157 result = smartlist_join_strings(lst, ", ", 0, NULL);
158 } else {
159 result = tor_strdup("[Not an authority]");
161 smartlist_free(lst);
162 return result;
165 /** Return a string describing a given directory connection purpose. */
166 STATIC const char *
167 dir_conn_purpose_to_string(int purpose)
169 switch (purpose)
171 case DIR_PURPOSE_UPLOAD_DIR:
172 return "server descriptor upload";
173 case DIR_PURPOSE_UPLOAD_VOTE:
174 return "server vote upload";
175 case DIR_PURPOSE_UPLOAD_SIGNATURES:
176 return "consensus signature upload";
177 case DIR_PURPOSE_FETCH_SERVERDESC:
178 return "server descriptor fetch";
179 case DIR_PURPOSE_FETCH_EXTRAINFO:
180 return "extra-info fetch";
181 case DIR_PURPOSE_FETCH_CONSENSUS:
182 return "consensus network-status fetch";
183 case DIR_PURPOSE_FETCH_CERTIFICATE:
184 return "authority cert fetch";
185 case DIR_PURPOSE_FETCH_STATUS_VOTE:
186 return "status vote fetch";
187 case DIR_PURPOSE_FETCH_DETACHED_SIGNATURES:
188 return "consensus signature fetch";
189 case DIR_PURPOSE_FETCH_RENDDESC_V2:
190 return "hidden-service v2 descriptor fetch";
191 case DIR_PURPOSE_UPLOAD_RENDDESC_V2:
192 return "hidden-service v2 descriptor upload";
193 case DIR_PURPOSE_FETCH_MICRODESC:
194 return "microdescriptor fetch";
197 log_warn(LD_BUG, "Called with unknown purpose %d", purpose);
198 return "(unknown)";
201 /** Return the requisite directory information types. */
202 STATIC dirinfo_type_t
203 dir_fetch_type(int dir_purpose, int router_purpose, const char *resource)
205 dirinfo_type_t type;
206 switch (dir_purpose) {
207 case DIR_PURPOSE_FETCH_EXTRAINFO:
208 type = EXTRAINFO_DIRINFO;
209 if (router_purpose == ROUTER_PURPOSE_BRIDGE)
210 type |= BRIDGE_DIRINFO;
211 else
212 type |= V3_DIRINFO;
213 break;
214 case DIR_PURPOSE_FETCH_SERVERDESC:
215 if (router_purpose == ROUTER_PURPOSE_BRIDGE)
216 type = BRIDGE_DIRINFO;
217 else
218 type = V3_DIRINFO;
219 break;
220 case DIR_PURPOSE_FETCH_STATUS_VOTE:
221 case DIR_PURPOSE_FETCH_DETACHED_SIGNATURES:
222 case DIR_PURPOSE_FETCH_CERTIFICATE:
223 type = V3_DIRINFO;
224 break;
225 case DIR_PURPOSE_FETCH_CONSENSUS:
226 type = V3_DIRINFO;
227 if (resource && !strcmp(resource, "microdesc"))
228 type |= MICRODESC_DIRINFO;
229 break;
230 case DIR_PURPOSE_FETCH_MICRODESC:
231 type = MICRODESC_DIRINFO;
232 break;
233 default:
234 log_warn(LD_BUG, "Unexpected purpose %d", (int)dir_purpose);
235 type = NO_DIRINFO;
236 break;
238 return type;
241 /** Return true iff <b>identity_digest</b> is the digest of a router which
242 * says that it caches extrainfos. (If <b>is_authority</b> we always
243 * believe that to be true.) */
245 router_supports_extrainfo(const char *identity_digest, int is_authority)
247 const node_t *node = node_get_by_id(identity_digest);
249 if (node && node->ri) {
250 if (node->ri->caches_extra_info)
251 return 1;
253 if (is_authority) {
254 return 1;
256 return 0;
259 /** Return true iff any trusted directory authority has accepted our
260 * server descriptor.
262 * We consider any authority sufficient because waiting for all of
263 * them means it never happens while any authority is down; we don't
264 * go for something more complex in the middle (like \>1/3 or \>1/2 or
265 * \>=1/2) because that doesn't seem necessary yet.
268 directories_have_accepted_server_descriptor(void)
270 const smartlist_t *servers = router_get_trusted_dir_servers();
271 const or_options_t *options = get_options();
272 SMARTLIST_FOREACH(servers, dir_server_t *, d, {
273 if ((d->type & options->PublishServerDescriptor_) &&
274 d->has_accepted_serverdesc) {
275 return 1;
278 return 0;
281 /** Start a connection to every suitable directory authority, using
282 * connection purpose <b>dir_purpose</b> and uploading <b>payload</b>
283 * (of length <b>payload_len</b>). The dir_purpose should be one of
284 * 'DIR_PURPOSE_UPLOAD_{DIR|VOTE|SIGNATURES}'.
286 * <b>router_purpose</b> describes the type of descriptor we're
287 * publishing, if we're publishing a descriptor -- e.g. general or bridge.
289 * <b>type</b> specifies what sort of dir authorities (V3,
290 * BRIDGE, etc) we should upload to.
292 * If <b>extrainfo_len</b> is nonzero, the first <b>payload_len</b> bytes of
293 * <b>payload</b> hold a router descriptor, and the next <b>extrainfo_len</b>
294 * bytes of <b>payload</b> hold an extra-info document. Upload the descriptor
295 * to all authorities, and the extra-info document to all authorities that
296 * support it.
298 void
299 directory_post_to_dirservers(uint8_t dir_purpose, uint8_t router_purpose,
300 dirinfo_type_t type,
301 const char *payload,
302 size_t payload_len, size_t extrainfo_len)
304 const or_options_t *options = get_options();
305 dir_indirection_t indirection;
306 const smartlist_t *dirservers = router_get_trusted_dir_servers();
307 int found = 0;
308 const int exclude_self = (dir_purpose == DIR_PURPOSE_UPLOAD_VOTE ||
309 dir_purpose == DIR_PURPOSE_UPLOAD_SIGNATURES);
310 tor_assert(dirservers);
311 /* This tries dirservers which we believe to be down, but ultimately, that's
312 * harmless, and we may as well err on the side of getting things uploaded.
314 SMARTLIST_FOREACH_BEGIN(dirservers, dir_server_t *, ds) {
315 routerstatus_t *rs = &(ds->fake_status);
316 size_t upload_len = payload_len;
318 if ((type & ds->type) == 0)
319 continue;
321 if (exclude_self && router_digest_is_me(ds->digest)) {
322 /* we don't upload to ourselves, but at least there's now at least
323 * one authority of this type that has what we wanted to upload. */
324 found = 1;
325 continue;
328 if (options->StrictNodes &&
329 routerset_contains_routerstatus(options->ExcludeNodes, rs, -1)) {
330 log_warn(LD_DIR, "Wanted to contact authority '%s' for %s, but "
331 "it's in our ExcludedNodes list and StrictNodes is set. "
332 "Skipping.",
333 ds->nickname,
334 dir_conn_purpose_to_string(dir_purpose));
335 continue;
338 found = 1; /* at least one authority of this type was listed */
339 if (dir_purpose == DIR_PURPOSE_UPLOAD_DIR)
340 ds->has_accepted_serverdesc = 0;
342 if (extrainfo_len && router_supports_extrainfo(ds->digest, 1)) {
343 upload_len += extrainfo_len;
344 log_info(LD_DIR, "Uploading an extrainfo too (length %d)",
345 (int) extrainfo_len);
347 if (purpose_needs_anonymity(dir_purpose, router_purpose)) {
348 indirection = DIRIND_ANONYMOUS;
349 } else if (!fascist_firewall_allows_dir_server(ds,
350 FIREWALL_DIR_CONNECTION,
351 0)) {
352 if (fascist_firewall_allows_dir_server(ds, FIREWALL_OR_CONNECTION, 0))
353 indirection = DIRIND_ONEHOP;
354 else
355 indirection = DIRIND_ANONYMOUS;
356 } else {
357 indirection = DIRIND_DIRECT_CONN;
359 directory_initiate_command_routerstatus(rs, dir_purpose,
360 router_purpose,
361 indirection,
362 NULL, payload, upload_len, 0);
363 } SMARTLIST_FOREACH_END(ds);
364 if (!found) {
365 char *s = authdir_type_to_string(type);
366 log_warn(LD_DIR, "Publishing server descriptor to directory authorities "
367 "of type '%s', but no authorities of that type listed!", s);
368 tor_free(s);
372 /** Return true iff, according to the values in <b>options</b>, we should be
373 * using directory guards for direct downloads of directory information. */
374 STATIC int
375 should_use_directory_guards(const or_options_t *options)
377 /* Public (non-bridge) servers never use directory guards. */
378 if (public_server_mode(options))
379 return 0;
380 /* If guards are disabled, or directory guards are disabled, we can't
381 * use directory guards.
383 if (!options->UseEntryGuards || !options->UseEntryGuardsAsDirGuards)
384 return 0;
385 /* If we're configured to fetch directory info aggressively or of a
386 * nonstandard type, don't use directory guards. */
387 if (options->DownloadExtraInfo || options->FetchDirInfoEarly ||
388 options->FetchDirInfoExtraEarly || options->FetchUselessDescriptors)
389 return 0;
390 return 1;
393 /** Pick an unconstrained directory server from among our guards, the latest
394 * networkstatus, or the fallback dirservers, for use in downloading
395 * information of type <b>type</b>, and return its routerstatus. */
396 static const routerstatus_t *
397 directory_pick_generic_dirserver(dirinfo_type_t type, int pds_flags,
398 uint8_t dir_purpose)
400 const routerstatus_t *rs = NULL;
401 const or_options_t *options = get_options();
403 if (options->UseBridges)
404 log_warn(LD_BUG, "Called when we have UseBridges set.");
406 if (should_use_directory_guards(options)) {
407 const node_t *node = choose_random_dirguard(type);
408 if (node)
409 rs = node->rs;
410 } else {
411 /* anybody with a non-zero dirport will do */
412 rs = router_pick_directory_server(type, pds_flags);
414 if (!rs) {
415 log_info(LD_DIR, "No router found for %s; falling back to "
416 "dirserver list.", dir_conn_purpose_to_string(dir_purpose));
417 rs = router_pick_fallback_dirserver(type, pds_flags);
420 return rs;
423 /** Start a connection to a random running directory server, using
424 * connection purpose <b>dir_purpose</b>, intending to fetch descriptors
425 * of purpose <b>router_purpose</b>, and requesting <b>resource</b>.
426 * Use <b>pds_flags</b> as arguments to router_pick_directory_server()
427 * or router_pick_trusteddirserver().
429 MOCK_IMPL(void, directory_get_from_dirserver, (
430 uint8_t dir_purpose,
431 uint8_t router_purpose,
432 const char *resource,
433 int pds_flags,
434 download_want_authority_t want_authority))
436 const routerstatus_t *rs = NULL;
437 const or_options_t *options = get_options();
438 int prefer_authority = (directory_fetches_from_authorities(options)
439 || want_authority == DL_WANT_AUTHORITY);
440 int require_authority = 0;
441 int get_via_tor = purpose_needs_anonymity(dir_purpose, router_purpose);
442 dirinfo_type_t type = dir_fetch_type(dir_purpose, router_purpose, resource);
443 time_t if_modified_since = 0;
445 if (type == NO_DIRINFO)
446 return;
448 if (dir_purpose == DIR_PURPOSE_FETCH_CONSENSUS) {
449 int flav = FLAV_NS;
450 networkstatus_t *v;
451 if (resource)
452 flav = networkstatus_parse_flavor_name(resource);
454 /* DEFAULT_IF_MODIFIED_SINCE_DELAY is 1/20 of the default consensus
455 * period of 1 hour.
457 #define DEFAULT_IF_MODIFIED_SINCE_DELAY (180)
458 if (flav != -1) {
459 /* IF we have a parsed consensus of this type, we can do an
460 * if-modified-time based on it. */
461 v = networkstatus_get_latest_consensus_by_flavor(flav);
462 if (v) {
463 /* In networks with particularly short V3AuthVotingIntervals,
464 * ask for the consensus if it's been modified since half the
465 * V3AuthVotingInterval of the most recent consensus. */
466 time_t ims_delay = DEFAULT_IF_MODIFIED_SINCE_DELAY;
467 if (v->fresh_until > v->valid_after
468 && ims_delay > (v->fresh_until - v->valid_after)/2) {
469 ims_delay = (v->fresh_until - v->valid_after)/2;
471 if_modified_since = v->valid_after + ims_delay;
473 } else {
474 /* Otherwise it might be a consensus we don't parse, but which we
475 * do cache. Look at the cached copy, perhaps. */
476 cached_dir_t *cd = dirserv_get_consensus(resource);
477 /* We have no method of determining the voting interval from an
478 * unparsed consensus, so we use the default. */
479 if (cd)
480 if_modified_since = cd->published + DEFAULT_IF_MODIFIED_SINCE_DELAY;
484 if (!options->FetchServerDescriptors)
485 return;
487 if (!get_via_tor) {
488 if (options->UseBridges && !(type & BRIDGE_DIRINFO)) {
489 /* We want to ask a running bridge for which we have a descriptor.
491 * When we ask choose_random_entry() for a bridge, we specify what
492 * sort of dir fetch we'll be doing, so it won't return a bridge
493 * that can't answer our question.
495 /* XXX024 Not all bridges handle conditional consensus downloading,
496 * so, for now, never assume the server supports that. -PP */
497 const node_t *node = choose_random_dirguard(type);
498 if (node && node->ri) {
499 /* every bridge has a routerinfo. */
500 routerinfo_t *ri = node->ri;
501 /* clients always make OR connections to bridges */
502 tor_addr_port_t or_ap;
503 /* we are willing to use a non-preferred address if we need to */
504 fascist_firewall_choose_address_node(node, FIREWALL_OR_CONNECTION, 0,
505 &or_ap);
506 directory_initiate_command(&or_ap.addr, or_ap.port,
507 NULL, 0, /*no dirport*/
508 ri->cache_info.identity_digest,
509 dir_purpose,
510 router_purpose,
511 DIRIND_ONEHOP,
512 resource, NULL, 0, if_modified_since);
513 } else
514 log_notice(LD_DIR, "Ignoring directory request, since no bridge "
515 "nodes are available yet.");
516 return;
517 } else {
518 if (prefer_authority || (type & BRIDGE_DIRINFO)) {
519 /* only ask authdirservers, and don't ask myself */
520 rs = router_pick_trusteddirserver(type, pds_flags);
521 if (rs == NULL && (pds_flags & (PDS_NO_EXISTING_SERVERDESC_FETCH|
522 PDS_NO_EXISTING_MICRODESC_FETCH))) {
523 /* We don't want to fetch from any authorities that we're currently
524 * fetching server descriptors from, and we got no match. Did we
525 * get no match because all the authorities have connections
526 * fetching server descriptors (in which case we should just
527 * return,) or because all the authorities are down or on fire or
528 * unreachable or something (in which case we should go on with
529 * our fallback code)? */
530 pds_flags &= ~(PDS_NO_EXISTING_SERVERDESC_FETCH|
531 PDS_NO_EXISTING_MICRODESC_FETCH);
532 rs = router_pick_trusteddirserver(type, pds_flags);
533 if (rs) {
534 log_debug(LD_DIR, "Deferring serverdesc fetch: all authorities "
535 "are in use.");
536 return;
539 if (rs == NULL && require_authority) {
540 log_info(LD_DIR, "No authorities were available for %s: will try "
541 "later.", dir_conn_purpose_to_string(dir_purpose));
542 return;
545 if (!rs && !(type & BRIDGE_DIRINFO)) {
546 /* */
547 rs = directory_pick_generic_dirserver(type, pds_flags,
548 dir_purpose);
549 if (!rs)
550 get_via_tor = 1; /* last resort: try routing it via Tor */
555 if (get_via_tor) {
556 /* Never use fascistfirewall; we're going via Tor. */
557 pds_flags |= PDS_IGNORE_FASCISTFIREWALL;
558 rs = router_pick_directory_server(type, pds_flags);
561 /* If we have any hope of building an indirect conn, we know some router
562 * descriptors. If (rs==NULL), we can't build circuits anyway, so
563 * there's no point in falling back to the authorities in this case. */
564 if (rs) {
565 const dir_indirection_t indirection =
566 get_via_tor ? DIRIND_ANONYMOUS : DIRIND_ONEHOP;
567 directory_initiate_command_routerstatus(rs, dir_purpose,
568 router_purpose,
569 indirection,
570 resource, NULL, 0,
571 if_modified_since);
572 } else {
573 log_notice(LD_DIR,
574 "While fetching directory info, "
575 "no running dirservers known. Will try again later. "
576 "(purpose %d)", dir_purpose);
577 if (!purpose_needs_anonymity(dir_purpose, router_purpose)) {
578 /* remember we tried them all and failed. */
579 directory_all_unreachable(time(NULL));
584 /** As directory_get_from_dirserver, but initiates a request to <i>every</i>
585 * directory authority other than ourself. Only for use by authorities when
586 * searching for missing information while voting. */
587 void
588 directory_get_from_all_authorities(uint8_t dir_purpose,
589 uint8_t router_purpose,
590 const char *resource)
592 tor_assert(dir_purpose == DIR_PURPOSE_FETCH_STATUS_VOTE ||
593 dir_purpose == DIR_PURPOSE_FETCH_DETACHED_SIGNATURES);
595 SMARTLIST_FOREACH_BEGIN(router_get_trusted_dir_servers(),
596 dir_server_t *, ds) {
597 routerstatus_t *rs;
598 if (router_digest_is_me(ds->digest))
599 continue;
600 if (!(ds->type & V3_DIRINFO))
601 continue;
602 rs = &ds->fake_status;
603 directory_initiate_command_routerstatus(rs, dir_purpose, router_purpose,
604 DIRIND_ONEHOP, resource, NULL,
605 0, 0);
606 } SMARTLIST_FOREACH_END(ds);
609 /** Return true iff <b>ind</b> requires a multihop circuit. */
610 static int
611 dirind_is_anon(dir_indirection_t ind)
613 return ind == DIRIND_ANON_DIRPORT || ind == DIRIND_ANONYMOUS;
616 /* Choose reachable OR and Dir addresses and ports from status, copying them
617 * into use_or_ap and use_dir_ap. If indirection is anonymous, then we're
618 * connecting via another relay, so choose the primary IPv4 address and ports.
620 * status should have at least one reachable address, if we can't choose a
621 * reachable address, warn and return -1. Otherwise, return 0.
623 static int
624 directory_choose_address_routerstatus(const routerstatus_t *status,
625 dir_indirection_t indirection,
626 tor_addr_port_t *use_or_ap,
627 tor_addr_port_t *use_dir_ap)
629 tor_assert(status != NULL);
630 tor_assert(use_or_ap != NULL);
631 tor_assert(use_dir_ap != NULL);
633 const int anonymized_connection = dirind_is_anon(indirection);
634 int have_or = 0, have_dir = 0;
636 /* We expect status to have at least one reachable address if we're
637 * connecting to it directly.
639 * Therefore, we can simply use the other address if the one we want isn't
640 * allowed by the firewall.
642 * (When Tor uploads and downloads a hidden service descriptor, it uses
643 * DIRIND_ANONYMOUS, except for Tor2Web, which uses DIRIND_ONEHOP.
644 * So this code will only modify the address for Tor2Web's HS descriptor
645 * fetches. Even Single Onion Servers (NYI) use DIRIND_ANONYMOUS, to avoid
646 * HSDirs denying service by rejecting descriptors.)
649 /* Initialise the OR / Dir addresses */
650 tor_addr_make_null(&use_or_ap->addr, AF_UNSPEC);
651 use_or_ap->port = 0;
652 tor_addr_make_null(&use_dir_ap->addr, AF_UNSPEC);
653 use_dir_ap->port = 0;
655 if (anonymized_connection) {
656 /* Use the primary (IPv4) OR address if we're making an indirect
657 * connection. */
658 tor_addr_from_ipv4h(&use_or_ap->addr, status->addr);
659 use_or_ap->port = status->or_port;
660 have_or = 1;
661 } else {
662 /* We use an IPv6 address if we have one and we prefer it.
663 * Use the preferred address and port if they are reachable, otherwise,
664 * use the alternate address and port (if any).
666 have_or = fascist_firewall_choose_address_rs(status,
667 FIREWALL_OR_CONNECTION, 0,
668 use_or_ap);
671 have_dir = fascist_firewall_choose_address_rs(status,
672 FIREWALL_DIR_CONNECTION, 0,
673 use_dir_ap);
675 /* We rejected both addresses. This isn't great. */
676 if (!have_or && !have_dir) {
677 log_warn(LD_BUG, "Rejected all OR and Dir addresses from %s when "
678 "launching a directory connection to: IPv4 %s OR %d Dir %d "
679 "IPv6 %s OR %d Dir %d", routerstatus_describe(status),
680 fmt_addr32(status->addr), status->or_port,
681 status->dir_port, fmt_addr(&status->ipv6_addr),
682 status->ipv6_orport, status->dir_port);
683 log_backtrace(LOG_WARN, LD_BUG, "Addresses came from");
684 return -1;
687 return 0;
690 /** Same as directory_initiate_command_routerstatus(), but accepts
691 * rendezvous data to fetch a hidden service descriptor. */
692 void
693 directory_initiate_command_routerstatus_rend(const routerstatus_t *status,
694 uint8_t dir_purpose,
695 uint8_t router_purpose,
696 dir_indirection_t indirection,
697 const char *resource,
698 const char *payload,
699 size_t payload_len,
700 time_t if_modified_since,
701 const rend_data_t *rend_query)
703 const or_options_t *options = get_options();
704 const node_t *node;
705 tor_addr_port_t use_or_ap, use_dir_ap;
706 const int anonymized_connection = dirind_is_anon(indirection);
708 tor_assert(status != NULL);
710 node = node_get_by_id(status->identity_digest);
712 if (!node && anonymized_connection) {
713 log_info(LD_DIR, "Not sending anonymized request to directory '%s'; we "
714 "don't have its router descriptor.",
715 routerstatus_describe(status));
716 return;
719 if (options->ExcludeNodes && options->StrictNodes &&
720 routerset_contains_routerstatus(options->ExcludeNodes, status, -1)) {
721 log_warn(LD_DIR, "Wanted to contact directory mirror %s for %s, but "
722 "it's in our ExcludedNodes list and StrictNodes is set. "
723 "Skipping. This choice might make your Tor not work.",
724 routerstatus_describe(status),
725 dir_conn_purpose_to_string(dir_purpose));
726 return;
729 /* At this point, if we are a clients making a direct connection to a
730 * directory server, we have selected a server that has at least one address
731 * allowed by ClientUseIPv4/6 and Reachable{"",OR,Dir}Addresses. This
732 * selection uses the preference in ClientPreferIPv6{OR,Dir}Port, if
733 * possible. (If UseBridges is set, clients always use IPv6, and prefer it
734 * by default.)
736 * Now choose an address that we can use to connect to the directory server.
738 if (directory_choose_address_routerstatus(status, indirection, &use_or_ap,
739 &use_dir_ap) < 0) {
740 return;
743 /* We don't retry the alternate OR/Dir address for the same directory if
744 * the address we choose fails (#6772).
745 * Instead, we'll retry another directory on failure. */
747 directory_initiate_command_rend(&use_or_ap, &use_dir_ap,
748 status->identity_digest,
749 dir_purpose, router_purpose,
750 indirection, resource,
751 payload, payload_len, if_modified_since,
752 rend_query);
755 /** Launch a new connection to the directory server <b>status</b> to
756 * upload or download a server or rendezvous
757 * descriptor. <b>dir_purpose</b> determines what
758 * kind of directory connection we're launching, and must be one of
759 * DIR_PURPOSE_{FETCH|UPLOAD}_{DIR|RENDDESC_V2}. <b>router_purpose</b>
760 * specifies the descriptor purposes we have in mind (currently only
761 * used for FETCH_DIR).
763 * When uploading, <b>payload</b> and <b>payload_len</b> determine the content
764 * of the HTTP post. Otherwise, <b>payload</b> should be NULL.
766 * When fetching a rendezvous descriptor, <b>resource</b> is the service ID we
767 * want to fetch.
769 MOCK_IMPL(void, directory_initiate_command_routerstatus,
770 (const routerstatus_t *status,
771 uint8_t dir_purpose,
772 uint8_t router_purpose,
773 dir_indirection_t indirection,
774 const char *resource,
775 const char *payload,
776 size_t payload_len,
777 time_t if_modified_since))
779 directory_initiate_command_routerstatus_rend(status, dir_purpose,
780 router_purpose,
781 indirection, resource,
782 payload, payload_len,
783 if_modified_since, NULL);
786 /** Return true iff <b>conn</b> is the client side of a directory connection
787 * we launched to ourself in order to determine the reachability of our
788 * dir_port. */
789 static int
790 directory_conn_is_self_reachability_test(dir_connection_t *conn)
792 if (conn->requested_resource &&
793 !strcmpstart(conn->requested_resource,"authority")) {
794 const routerinfo_t *me = router_get_my_routerinfo();
795 if (me &&
796 router_digest_is_me(conn->identity_digest) &&
797 tor_addr_eq_ipv4h(&conn->base_.addr, me->addr) && /*XXXX prop 118*/
798 me->dir_port == conn->base_.port)
799 return 1;
801 return 0;
804 /** Called when we are unable to complete the client's request to a directory
805 * server due to a network error: Mark the router as down and try again if
806 * possible.
808 static void
809 connection_dir_request_failed(dir_connection_t *conn)
811 if (directory_conn_is_self_reachability_test(conn)) {
812 return; /* this was a test fetch. don't retry. */
814 if (!entry_list_is_constrained(get_options()))
815 router_set_status(conn->identity_digest, 0); /* don't try this one again */
816 if (conn->base_.purpose == DIR_PURPOSE_FETCH_SERVERDESC ||
817 conn->base_.purpose == DIR_PURPOSE_FETCH_EXTRAINFO) {
818 log_info(LD_DIR, "Giving up on serverdesc/extrainfo fetch from "
819 "directory server at '%s'; retrying",
820 conn->base_.address);
821 if (conn->router_purpose == ROUTER_PURPOSE_BRIDGE)
822 connection_dir_bridge_routerdesc_failed(conn);
823 connection_dir_download_routerdesc_failed(conn);
824 } else if (conn->base_.purpose == DIR_PURPOSE_FETCH_CONSENSUS) {
825 if (conn->requested_resource)
826 networkstatus_consensus_download_failed(0, conn->requested_resource);
827 } else if (conn->base_.purpose == DIR_PURPOSE_FETCH_CERTIFICATE) {
828 log_info(LD_DIR, "Giving up on certificate fetch from directory server "
829 "at '%s'; retrying",
830 conn->base_.address);
831 connection_dir_download_cert_failed(conn, 0);
832 } else if (conn->base_.purpose == DIR_PURPOSE_FETCH_DETACHED_SIGNATURES) {
833 log_info(LD_DIR, "Giving up downloading detached signatures from '%s'",
834 conn->base_.address);
835 } else if (conn->base_.purpose == DIR_PURPOSE_FETCH_STATUS_VOTE) {
836 log_info(LD_DIR, "Giving up downloading votes from '%s'",
837 conn->base_.address);
838 } else if (conn->base_.purpose == DIR_PURPOSE_FETCH_MICRODESC) {
839 log_info(LD_DIR, "Giving up on downloading microdescriptors from "
840 "directory server at '%s'; will retry", conn->base_.address);
841 connection_dir_download_routerdesc_failed(conn);
845 /** Helper: Attempt to fetch directly the descriptors of each bridge
846 * listed in <b>failed</b>.
848 static void
849 connection_dir_retry_bridges(smartlist_t *descs)
851 char digest[DIGEST_LEN];
852 SMARTLIST_FOREACH(descs, const char *, cp,
854 if (base16_decode(digest, DIGEST_LEN, cp, strlen(cp))<0) {
855 log_warn(LD_BUG, "Malformed fingerprint in list: %s",
856 escaped(cp));
857 continue;
859 retry_bridge_descriptor_fetch_directly(digest);
863 /** Called when an attempt to download one or more router descriptors
864 * or extra-info documents on connection <b>conn</b> failed.
866 static void
867 connection_dir_download_routerdesc_failed(dir_connection_t *conn)
869 /* No need to increment the failure count for routerdescs, since
870 * it's not their fault. */
872 /* No need to relaunch descriptor downloads here: we already do it
873 * every 10 or 60 seconds (FOO_DESCRIPTOR_RETRY_INTERVAL) in main.c. */
874 tor_assert(conn->base_.purpose == DIR_PURPOSE_FETCH_SERVERDESC ||
875 conn->base_.purpose == DIR_PURPOSE_FETCH_EXTRAINFO ||
876 conn->base_.purpose == DIR_PURPOSE_FETCH_MICRODESC);
878 (void) conn;
881 /** Called when an attempt to download a bridge's routerdesc from
882 * one of the authorities failed due to a network error. If
883 * possible attempt to download descriptors from the bridge directly.
885 static void
886 connection_dir_bridge_routerdesc_failed(dir_connection_t *conn)
888 smartlist_t *which = NULL;
890 /* Requests for bridge descriptors are in the form 'fp/', so ignore
891 anything else. */
892 if (!conn->requested_resource || strcmpstart(conn->requested_resource,"fp/"))
893 return;
895 which = smartlist_new();
896 dir_split_resource_into_fingerprints(conn->requested_resource
897 + strlen("fp/"),
898 which, NULL, 0);
900 tor_assert(conn->base_.purpose != DIR_PURPOSE_FETCH_EXTRAINFO);
901 if (smartlist_len(which)) {
902 connection_dir_retry_bridges(which);
903 SMARTLIST_FOREACH(which, char *, cp, tor_free(cp));
905 smartlist_free(which);
908 /** Called when an attempt to fetch a certificate fails. */
909 static void
910 connection_dir_download_cert_failed(dir_connection_t *conn, int status)
912 const char *fp_pfx = "fp/";
913 const char *fpsk_pfx = "fp-sk/";
914 smartlist_t *failed;
915 tor_assert(conn->base_.purpose == DIR_PURPOSE_FETCH_CERTIFICATE);
917 if (!conn->requested_resource)
918 return;
919 failed = smartlist_new();
921 * We have two cases download by fingerprint (resource starts
922 * with "fp/") or download by fingerprint/signing key pair
923 * (resource starts with "fp-sk/").
925 if (!strcmpstart(conn->requested_resource, fp_pfx)) {
926 /* Download by fingerprint case */
927 dir_split_resource_into_fingerprints(conn->requested_resource +
928 strlen(fp_pfx),
929 failed, NULL, DSR_HEX);
930 SMARTLIST_FOREACH_BEGIN(failed, char *, cp) {
931 /* Null signing key digest indicates download by fp only */
932 authority_cert_dl_failed(cp, NULL, status);
933 tor_free(cp);
934 } SMARTLIST_FOREACH_END(cp);
935 } else if (!strcmpstart(conn->requested_resource, fpsk_pfx)) {
936 /* Download by (fp,sk) pairs */
937 dir_split_resource_into_fingerprint_pairs(conn->requested_resource +
938 strlen(fpsk_pfx), failed);
939 SMARTLIST_FOREACH_BEGIN(failed, fp_pair_t *, cp) {
940 authority_cert_dl_failed(cp->first, cp->second, status);
941 tor_free(cp);
942 } SMARTLIST_FOREACH_END(cp);
943 } else {
944 log_warn(LD_DIR,
945 "Don't know what to do with failure for cert fetch %s",
946 conn->requested_resource);
949 smartlist_free(failed);
951 update_certificate_downloads(time(NULL));
954 /** Evaluate the situation and decide if we should use an encrypted
955 * "begindir-style" connection for this directory request.
956 * 1) If or_port is 0, or it's a direct conn and or_port is firewalled
957 * or we're a dir mirror, no.
958 * 2) If we prefer to avoid begindir conns, and we're not fetching or
959 * publishing a bridge relay descriptor, no.
960 * 3) Else yes.
962 static int
963 directory_command_should_use_begindir(const or_options_t *options,
964 const tor_addr_t *addr,
965 int or_port, uint8_t router_purpose,
966 dir_indirection_t indirection)
968 (void) router_purpose;
969 if (!or_port)
970 return 0; /* We don't know an ORPort -- no chance. */
971 if (indirection == DIRIND_DIRECT_CONN || indirection == DIRIND_ANON_DIRPORT)
972 return 0;
973 if (indirection == DIRIND_ONEHOP)
974 if (!fascist_firewall_allows_address_addr(addr, or_port,
975 FIREWALL_OR_CONNECTION, 0, 0) ||
976 directory_fetches_from_authorities(options))
977 return 0; /* We're firewalled or are acting like a relay -- also no. */
978 return 1;
981 /** Helper for directory_initiate_command_rend: send the
982 * command to a server whose OR address/port is <b>or_addr</b>/<b>or_port</b>,
983 * whose directory address/port is <b>dir_addr</b>/<b>dir_port</b>, whose
984 * identity key digest is <b>digest</b>, with purposes <b>dir_purpose</b> and
985 * <b>router_purpose</b>, making an (in)direct connection as specified in
986 * <b>indirection</b>, with command <b>resource</b>, <b>payload</b> of
987 * <b>payload_len</b>, and asking for a result only <b>if_modified_since</b>.
989 void
990 directory_initiate_command(const tor_addr_t *or_addr, uint16_t or_port,
991 const tor_addr_t *dir_addr, uint16_t dir_port,
992 const char *digest,
993 uint8_t dir_purpose, uint8_t router_purpose,
994 dir_indirection_t indirection, const char *resource,
995 const char *payload, size_t payload_len,
996 time_t if_modified_since)
998 tor_addr_port_t or_ap, dir_ap;
1000 /* Use the null tor_addr and 0 port if the address or port isn't valid. */
1001 if (tor_addr_port_is_valid(or_addr, or_port, 0)) {
1002 tor_addr_copy(&or_ap.addr, or_addr);
1003 or_ap.port = or_port;
1004 } else {
1005 /* the family doesn't matter here, so make it IPv4 */
1006 tor_addr_make_null(&or_ap.addr, AF_INET);
1007 or_ap.port = or_port = 0;
1010 if (tor_addr_port_is_valid(dir_addr, dir_port, 0)) {
1011 tor_addr_copy(&dir_ap.addr, dir_addr);
1012 dir_ap.port = dir_port;
1013 } else {
1014 /* the family doesn't matter here, so make it IPv4 */
1015 tor_addr_make_null(&dir_ap.addr, AF_INET);
1016 dir_ap.port = dir_port = 0;
1019 directory_initiate_command_rend(&or_ap, &dir_ap,
1020 digest, dir_purpose,
1021 router_purpose, indirection,
1022 resource, payload, payload_len,
1023 if_modified_since, NULL);
1026 /** Return non-zero iff a directory connection with purpose
1027 * <b>dir_purpose</b> reveals sensitive information about a Tor
1028 * instance's client activities. (Such connections must be performed
1029 * through normal three-hop Tor circuits.) */
1030 static int
1031 is_sensitive_dir_purpose(uint8_t dir_purpose)
1033 return ((dir_purpose == DIR_PURPOSE_HAS_FETCHED_RENDDESC_V2) ||
1034 (dir_purpose == DIR_PURPOSE_UPLOAD_RENDDESC_V2) ||
1035 (dir_purpose == DIR_PURPOSE_FETCH_RENDDESC_V2));
1038 /** Same as directory_initiate_command(), but accepts rendezvous data to
1039 * fetch a hidden service descriptor, and takes its address & port arguments
1040 * as tor_addr_port_t. */
1041 static void
1042 directory_initiate_command_rend(const tor_addr_port_t *or_addr_port,
1043 const tor_addr_port_t *dir_addr_port,
1044 const char *digest,
1045 uint8_t dir_purpose, uint8_t router_purpose,
1046 dir_indirection_t indirection,
1047 const char *resource,
1048 const char *payload, size_t payload_len,
1049 time_t if_modified_since,
1050 const rend_data_t *rend_query)
1052 tor_assert(or_addr_port);
1053 tor_assert(dir_addr_port);
1054 tor_assert(or_addr_port->port || dir_addr_port->port);
1055 tor_assert(digest);
1057 dir_connection_t *conn;
1058 const or_options_t *options = get_options();
1059 int socket_error = 0;
1060 const int use_begindir = directory_command_should_use_begindir(options,
1061 &or_addr_port->addr, or_addr_port->port,
1062 router_purpose, indirection);
1063 const int anonymized_connection = dirind_is_anon(indirection);
1064 const int or_connection = use_begindir || anonymized_connection;
1066 tor_addr_t addr;
1067 tor_addr_copy(&addr, &(or_connection ? or_addr_port : dir_addr_port)->addr);
1068 uint16_t port = (or_connection ? or_addr_port : dir_addr_port)->port;
1069 uint16_t dir_port = dir_addr_port->port;
1071 log_debug(LD_DIR, "anonymized %d, use_begindir %d.",
1072 anonymized_connection, use_begindir);
1074 if (!dir_port && !use_begindir) {
1075 char ipaddr[TOR_ADDR_BUF_LEN];
1076 tor_addr_to_str(ipaddr, &addr, TOR_ADDR_BUF_LEN, 0);
1077 log_warn(LD_BUG, "Cannot use directory server without dirport or "
1078 "begindir! Address: %s, DirPort: %d, Connection Port: %d",
1079 escaped_safe_str_client(ipaddr), dir_port, port);
1080 return;
1083 log_debug(LD_DIR, "Initiating %s", dir_conn_purpose_to_string(dir_purpose));
1085 #ifndef NON_ANONYMOUS_MODE_ENABLED
1086 tor_assert(!(is_sensitive_dir_purpose(dir_purpose) &&
1087 !anonymized_connection));
1088 #else
1089 (void)is_sensitive_dir_purpose;
1090 #endif
1092 /* ensure that we don't make direct connections when a SOCKS server is
1093 * configured. */
1094 if (!or_connection && !options->HTTPProxy &&
1095 (options->Socks4Proxy || options->Socks5Proxy)) {
1096 log_warn(LD_DIR, "Cannot connect to a directory server through a "
1097 "SOCKS proxy!");
1098 return;
1101 if (or_connection && (!or_addr_port->port
1102 || tor_addr_is_null(&or_addr_port->addr))) {
1103 log_warn(LD_DIR, "Cannot make an OR connection without an OR port.");
1104 log_backtrace(LOG_WARN, LD_BUG, "Address came from");
1105 return;
1106 } else if (!or_connection && (!dir_addr_port->port
1107 || tor_addr_is_null(&dir_addr_port->addr))) {
1108 log_warn(LD_DIR, "Cannot make a Dir connection without a Dir port.");
1109 log_backtrace(LOG_WARN, LD_BUG, "Address came from");
1111 return;
1114 /* ensure we don't make excess connections when we're already downloading
1115 * a consensus during bootstrap */
1116 if (connection_dir_avoid_extra_connection_for_purpose(dir_purpose)) {
1117 return;
1120 conn = dir_connection_new(tor_addr_family(&addr));
1122 /* set up conn so it's got all the data we need to remember */
1123 tor_addr_copy(&conn->base_.addr, &addr);
1124 conn->base_.port = port;
1125 conn->base_.address = tor_dup_addr(&addr);
1126 memcpy(conn->identity_digest, digest, DIGEST_LEN);
1128 conn->base_.purpose = dir_purpose;
1129 conn->router_purpose = router_purpose;
1131 /* give it an initial state */
1132 conn->base_.state = DIR_CONN_STATE_CONNECTING;
1134 /* decide whether we can learn our IP address from this conn */
1135 /* XXXX This is a bad name for this field now. */
1136 conn->dirconn_direct = !anonymized_connection;
1138 /* copy rendezvous data, if any */
1139 if (rend_query)
1140 conn->rend_data = rend_data_dup(rend_query);
1142 if (!or_connection) {
1143 /* then we want to connect to dirport directly */
1145 if (options->HTTPProxy) {
1146 tor_addr_copy(&addr, &options->HTTPProxyAddr);
1147 dir_port = options->HTTPProxyPort;
1150 switch (connection_connect(TO_CONN(conn), conn->base_.address, &addr,
1151 dir_port, &socket_error)) {
1152 case -1:
1153 connection_mark_for_close(TO_CONN(conn));
1154 return;
1155 case 1:
1156 /* start flushing conn */
1157 conn->base_.state = DIR_CONN_STATE_CLIENT_SENDING;
1158 /* fall through */
1159 case 0:
1160 if (connection_dir_close_consensus_conn_if_extra(conn)) {
1161 return;
1163 /* queue the command on the outbuf */
1164 directory_send_command(conn, dir_purpose, 1, resource,
1165 payload, payload_len,
1166 if_modified_since);
1167 connection_watch_events(TO_CONN(conn), READ_EVENT | WRITE_EVENT);
1168 /* writable indicates finish, readable indicates broken link,
1169 error indicates broken link in windowsland. */
1171 } else { /* we want to connect via a tor connection */
1172 entry_connection_t *linked_conn;
1173 /* Anonymized tunneled connections can never share a circuit.
1174 * One-hop directory connections can share circuits with each other
1175 * but nothing else. */
1176 int iso_flags = anonymized_connection ? ISO_STREAM : ISO_SESSIONGRP;
1178 /* If it's an anonymized connection, remember the fact that we
1179 * wanted it for later: maybe we'll want it again soon. */
1180 if (anonymized_connection && use_begindir)
1181 rep_hist_note_used_internal(time(NULL), 0, 1);
1182 else if (anonymized_connection && !use_begindir)
1183 rep_hist_note_used_port(time(NULL), conn->base_.port);
1185 /* make an AP connection
1186 * populate it and add it at the right state
1187 * hook up both sides
1189 linked_conn =
1190 connection_ap_make_link(TO_CONN(conn),
1191 conn->base_.address, conn->base_.port,
1192 digest,
1193 SESSION_GROUP_DIRCONN, iso_flags,
1194 use_begindir, conn->dirconn_direct);
1195 if (!linked_conn) {
1196 log_warn(LD_NET,"Making tunnel to dirserver failed.");
1197 connection_mark_for_close(TO_CONN(conn));
1198 return;
1201 if (connection_add(TO_CONN(conn)) < 0) {
1202 log_warn(LD_NET,"Unable to add connection for link to dirserver.");
1203 connection_mark_for_close(TO_CONN(conn));
1204 return;
1206 if (connection_dir_close_consensus_conn_if_extra(conn)) {
1207 return;
1209 conn->base_.state = DIR_CONN_STATE_CLIENT_SENDING;
1210 /* queue the command on the outbuf */
1211 directory_send_command(conn, dir_purpose, 0, resource,
1212 payload, payload_len,
1213 if_modified_since);
1215 connection_watch_events(TO_CONN(conn), READ_EVENT|WRITE_EVENT);
1216 IF_HAS_BUFFEREVENT(ENTRY_TO_CONN(linked_conn), {
1217 connection_watch_events(ENTRY_TO_CONN(linked_conn),
1218 READ_EVENT|WRITE_EVENT);
1219 }) ELSE_IF_NO_BUFFEREVENT
1220 connection_start_reading(ENTRY_TO_CONN(linked_conn));
1224 /** Return true iff anything we say on <b>conn</b> is being encrypted before
1225 * we send it to the client/server. */
1227 connection_dir_is_encrypted(dir_connection_t *conn)
1229 /* Right now it's sufficient to see if conn is or has been linked, since
1230 * the only thing it could be linked to is an edge connection on a
1231 * circuit, and the only way it could have been unlinked is at the edge
1232 * connection getting closed.
1234 return TO_CONN(conn)->linked;
1237 /** Helper for sorting
1239 * sort strings alphabetically
1241 static int
1242 compare_strs_(const void **a, const void **b)
1244 const char *s1 = *a, *s2 = *b;
1245 return strcmp(s1, s2);
1248 #define CONDITIONAL_CONSENSUS_FPR_LEN 3
1249 #if (CONDITIONAL_CONSENSUS_FPR_LEN > DIGEST_LEN)
1250 #error "conditional consensus fingerprint length is larger than digest length"
1251 #endif
1253 /** Return the URL we should use for a consensus download.
1255 * This url depends on whether or not the server we go to
1256 * is sufficiently new to support conditional consensus downloading,
1257 * i.e. GET .../consensus/<b>fpr</b>+<b>fpr</b>+<b>fpr</b>
1259 * If 'resource' is provided, it is the name of a consensus flavor to request.
1261 static char *
1262 directory_get_consensus_url(const char *resource)
1264 char *url = NULL;
1265 const char *hyphen, *flavor;
1266 if (resource==NULL || strcmp(resource, "ns")==0) {
1267 flavor = ""; /* Request ns consensuses as "", so older servers will work*/
1268 hyphen = "";
1269 } else {
1270 flavor = resource;
1271 hyphen = "-";
1275 char *authority_id_list;
1276 smartlist_t *authority_digests = smartlist_new();
1278 SMARTLIST_FOREACH_BEGIN(router_get_trusted_dir_servers(),
1279 dir_server_t *, ds) {
1280 char *hex;
1281 if (!(ds->type & V3_DIRINFO))
1282 continue;
1284 hex = tor_malloc(2*CONDITIONAL_CONSENSUS_FPR_LEN+1);
1285 base16_encode(hex, 2*CONDITIONAL_CONSENSUS_FPR_LEN+1,
1286 ds->v3_identity_digest, CONDITIONAL_CONSENSUS_FPR_LEN);
1287 smartlist_add(authority_digests, hex);
1288 } SMARTLIST_FOREACH_END(ds);
1289 smartlist_sort(authority_digests, compare_strs_);
1290 authority_id_list = smartlist_join_strings(authority_digests,
1291 "+", 0, NULL);
1293 tor_asprintf(&url, "/tor/status-vote/current/consensus%s%s/%s.z",
1294 hyphen, flavor, authority_id_list);
1296 SMARTLIST_FOREACH(authority_digests, char *, cp, tor_free(cp));
1297 smartlist_free(authority_digests);
1298 tor_free(authority_id_list);
1300 return url;
1304 * Copies the ipv6 from source to destination, subject to buffer size limit
1305 * size. If decorate is true, makes sure the copied address is decorated.
1307 static void
1308 copy_ipv6_address(char* destination, const char* source, size_t len,
1309 int decorate) {
1310 tor_assert(destination);
1311 tor_assert(source);
1313 if (decorate && source[0] != '[') {
1314 tor_snprintf(destination, len, "[%s]", source);
1315 } else {
1316 strlcpy(destination, source, len);
1320 /** Queue an appropriate HTTP command on conn-\>outbuf. The other args
1321 * are as in directory_initiate_command().
1323 static void
1324 directory_send_command(dir_connection_t *conn,
1325 int purpose, int direct, const char *resource,
1326 const char *payload, size_t payload_len,
1327 time_t if_modified_since)
1329 char proxystring[256];
1330 char hoststring[128];
1331 /* NEEDS to be the same size hoststring.
1332 Will be decorated with brackets around it if it is ipv6. */
1333 char decorated_address[128];
1334 smartlist_t *headers = smartlist_new();
1335 char *url;
1336 char request[8192];
1337 const char *httpcommand = NULL;
1339 tor_assert(conn);
1340 tor_assert(conn->base_.type == CONN_TYPE_DIR);
1342 tor_free(conn->requested_resource);
1343 if (resource)
1344 conn->requested_resource = tor_strdup(resource);
1346 /* decorate the ip address if it is ipv6 */
1347 if (strchr(conn->base_.address, ':')) {
1348 copy_ipv6_address(decorated_address, conn->base_.address,
1349 sizeof(decorated_address), 1);
1350 } else {
1351 strlcpy(decorated_address, conn->base_.address, sizeof(decorated_address));
1354 /* come up with a string for which Host: we want */
1355 if (conn->base_.port == 80) {
1356 strlcpy(hoststring, decorated_address, sizeof(hoststring));
1357 } else {
1358 tor_snprintf(hoststring, sizeof(hoststring), "%s:%d",
1359 decorated_address, conn->base_.port);
1362 /* Format if-modified-since */
1363 if (if_modified_since) {
1364 char b[RFC1123_TIME_LEN+1];
1365 format_rfc1123_time(b, if_modified_since);
1366 smartlist_add_asprintf(headers, "If-Modified-Since: %s\r\n", b);
1369 /* come up with some proxy lines, if we're using one. */
1370 if (direct && get_options()->HTTPProxy) {
1371 char *base64_authenticator=NULL;
1372 const char *authenticator = get_options()->HTTPProxyAuthenticator;
1374 tor_snprintf(proxystring, sizeof(proxystring),"http://%s", hoststring);
1375 if (authenticator) {
1376 base64_authenticator = alloc_http_authenticator(authenticator);
1377 if (!base64_authenticator)
1378 log_warn(LD_BUG, "Encoding http authenticator failed");
1380 if (base64_authenticator) {
1381 smartlist_add_asprintf(headers,
1382 "Proxy-Authorization: Basic %s\r\n",
1383 base64_authenticator);
1384 tor_free(base64_authenticator);
1386 } else {
1387 proxystring[0] = 0;
1390 switch (purpose) {
1391 case DIR_PURPOSE_FETCH_CONSENSUS:
1392 /* resource is optional. If present, it's a flavor name */
1393 tor_assert(!payload);
1394 httpcommand = "GET";
1395 url = directory_get_consensus_url(resource);
1396 log_info(LD_DIR, "Downloading consensus from %s using %s",
1397 hoststring, url);
1398 break;
1399 case DIR_PURPOSE_FETCH_CERTIFICATE:
1400 tor_assert(resource);
1401 tor_assert(!payload);
1402 httpcommand = "GET";
1403 tor_asprintf(&url, "/tor/keys/%s", resource);
1404 break;
1405 case DIR_PURPOSE_FETCH_STATUS_VOTE:
1406 tor_assert(resource);
1407 tor_assert(!payload);
1408 httpcommand = "GET";
1409 tor_asprintf(&url, "/tor/status-vote/next/%s.z", resource);
1410 break;
1411 case DIR_PURPOSE_FETCH_DETACHED_SIGNATURES:
1412 tor_assert(!resource);
1413 tor_assert(!payload);
1414 httpcommand = "GET";
1415 url = tor_strdup("/tor/status-vote/next/consensus-signatures.z");
1416 break;
1417 case DIR_PURPOSE_FETCH_SERVERDESC:
1418 tor_assert(resource);
1419 httpcommand = "GET";
1420 tor_asprintf(&url, "/tor/server/%s", resource);
1421 break;
1422 case DIR_PURPOSE_FETCH_EXTRAINFO:
1423 tor_assert(resource);
1424 httpcommand = "GET";
1425 tor_asprintf(&url, "/tor/extra/%s", resource);
1426 break;
1427 case DIR_PURPOSE_FETCH_MICRODESC:
1428 tor_assert(resource);
1429 httpcommand = "GET";
1430 tor_asprintf(&url, "/tor/micro/%s", resource);
1431 break;
1432 case DIR_PURPOSE_UPLOAD_DIR: {
1433 const char *why = router_get_descriptor_gen_reason();
1434 tor_assert(!resource);
1435 tor_assert(payload);
1436 httpcommand = "POST";
1437 url = tor_strdup("/tor/");
1438 if (why) {
1439 smartlist_add_asprintf(headers, "X-Desc-Gen-Reason: %s\r\n", why);
1441 break;
1443 case DIR_PURPOSE_UPLOAD_VOTE:
1444 tor_assert(!resource);
1445 tor_assert(payload);
1446 httpcommand = "POST";
1447 url = tor_strdup("/tor/post/vote");
1448 break;
1449 case DIR_PURPOSE_UPLOAD_SIGNATURES:
1450 tor_assert(!resource);
1451 tor_assert(payload);
1452 httpcommand = "POST";
1453 url = tor_strdup("/tor/post/consensus-signature");
1454 break;
1455 case DIR_PURPOSE_FETCH_RENDDESC_V2:
1456 tor_assert(resource);
1457 tor_assert(strlen(resource) <= REND_DESC_ID_V2_LEN_BASE32);
1458 tor_assert(!payload);
1459 httpcommand = "GET";
1460 tor_asprintf(&url, "/tor/rendezvous2/%s", resource);
1461 break;
1462 case DIR_PURPOSE_UPLOAD_RENDDESC_V2:
1463 tor_assert(!resource);
1464 tor_assert(payload);
1465 httpcommand = "POST";
1466 url = tor_strdup("/tor/rendezvous2/publish");
1467 break;
1468 default:
1469 tor_assert(0);
1470 return;
1473 /* warn in the non-tunneled case */
1474 if (direct && (strlen(proxystring) + strlen(url) >= 4096)) {
1475 log_warn(LD_BUG,
1476 "Squid does not like URLs longer than 4095 bytes, and this "
1477 "one is %d bytes long: %s%s",
1478 (int)(strlen(proxystring) + strlen(url)), proxystring, url);
1481 tor_snprintf(request, sizeof(request), "%s %s", httpcommand, proxystring);
1482 connection_write_to_buf(request, strlen(request), TO_CONN(conn));
1483 connection_write_to_buf(url, strlen(url), TO_CONN(conn));
1484 tor_free(url);
1486 if (!strcmp(httpcommand, "POST") || payload) {
1487 smartlist_add_asprintf(headers, "Content-Length: %lu\r\n",
1488 payload ? (unsigned long)payload_len : 0);
1492 char *header = smartlist_join_strings(headers, "", 0, NULL);
1493 tor_snprintf(request, sizeof(request), " HTTP/1.0\r\nHost: %s\r\n%s\r\n",
1494 hoststring, header);
1495 tor_free(header);
1498 connection_write_to_buf(request, strlen(request), TO_CONN(conn));
1500 if (payload) {
1501 /* then send the payload afterwards too */
1502 connection_write_to_buf(payload, payload_len, TO_CONN(conn));
1505 SMARTLIST_FOREACH(headers, char *, h, tor_free(h));
1506 smartlist_free(headers);
1509 /** Parse an HTTP request string <b>headers</b> of the form
1510 * \verbatim
1511 * "\%s [http[s]://]\%s HTTP/1..."
1512 * \endverbatim
1513 * If it's well-formed, strdup the second \%s into *<b>url</b>, and
1514 * nul-terminate it. If the url doesn't start with "/tor/", rewrite it
1515 * so it does. Return 0.
1516 * Otherwise, return -1.
1518 STATIC int
1519 parse_http_url(const char *headers, char **url)
1521 char *s, *start, *tmp;
1523 s = (char *)eat_whitespace_no_nl(headers);
1524 if (!*s) return -1;
1525 s = (char *)find_whitespace(s); /* get past GET/POST */
1526 if (!*s) return -1;
1527 s = (char *)eat_whitespace_no_nl(s);
1528 if (!*s) return -1;
1529 start = s; /* this is it, assuming it's valid */
1530 s = (char *)find_whitespace(start);
1531 if (!*s) return -1;
1533 /* tolerate the http[s] proxy style of putting the hostname in the url */
1534 if (s-start >= 4 && !strcmpstart(start,"http")) {
1535 tmp = start + 4;
1536 if (*tmp == 's')
1537 tmp++;
1538 if (s-tmp >= 3 && !strcmpstart(tmp,"://")) {
1539 tmp = strchr(tmp+3, '/');
1540 if (tmp && tmp < s) {
1541 log_debug(LD_DIR,"Skipping over 'http[s]://hostname/' string");
1542 start = tmp;
1547 /* Check if the header is well formed (next sequence
1548 * should be HTTP/1.X\r\n). Assumes we're supporting 1.0? */
1550 unsigned minor_ver;
1551 char ch;
1552 char *e = (char *)eat_whitespace_no_nl(s);
1553 if (2 != tor_sscanf(e, "HTTP/1.%u%c", &minor_ver, &ch)) {
1554 return -1;
1556 if (ch != '\r')
1557 return -1;
1560 if (s-start < 5 || strcmpstart(start,"/tor/")) { /* need to rewrite it */
1561 *url = tor_malloc(s - start + 5);
1562 strlcpy(*url,"/tor", s-start+5);
1563 strlcat((*url)+4, start, s-start+1);
1564 } else {
1565 *url = tor_strndup(start, s-start);
1567 return 0;
1570 /** Return a copy of the first HTTP header in <b>headers</b> whose key is
1571 * <b>which</b>. The key should be given with a terminating colon and space;
1572 * this function copies everything after, up to but not including the
1573 * following \\r\\n. */
1574 static char *
1575 http_get_header(const char *headers, const char *which)
1577 const char *cp = headers;
1578 while (cp) {
1579 if (!strcasecmpstart(cp, which)) {
1580 char *eos;
1581 cp += strlen(which);
1582 if ((eos = strchr(cp,'\r')))
1583 return tor_strndup(cp, eos-cp);
1584 else
1585 return tor_strdup(cp);
1587 cp = strchr(cp, '\n');
1588 if (cp)
1589 ++cp;
1591 return NULL;
1594 /** If <b>headers</b> indicates that a proxy was involved, then rewrite
1595 * <b>conn</b>-\>address to describe our best guess of the address that
1596 * originated this HTTP request. */
1597 static void
1598 http_set_address_origin(const char *headers, connection_t *conn)
1600 char *fwd;
1602 fwd = http_get_header(headers, "Forwarded-For: ");
1603 if (!fwd)
1604 fwd = http_get_header(headers, "X-Forwarded-For: ");
1605 if (fwd) {
1606 tor_addr_t toraddr;
1607 if (tor_addr_parse(&toraddr,fwd) == -1 ||
1608 tor_addr_is_internal(&toraddr,0)) {
1609 log_debug(LD_DIR, "Ignoring local/internal IP %s", escaped(fwd));
1610 tor_free(fwd);
1611 return;
1614 tor_free(conn->address);
1615 conn->address = tor_strdup(fwd);
1616 tor_free(fwd);
1620 /** Parse an HTTP response string <b>headers</b> of the form
1621 * \verbatim
1622 * "HTTP/1.\%d \%d\%s\r\n...".
1623 * \endverbatim
1625 * If it's well-formed, assign the status code to *<b>code</b> and
1626 * return 0. Otherwise, return -1.
1628 * On success: If <b>date</b> is provided, set *date to the Date
1629 * header in the http headers, or 0 if no such header is found. If
1630 * <b>compression</b> is provided, set *<b>compression</b> to the
1631 * compression method given in the Content-Encoding header, or 0 if no
1632 * such header is found, or -1 if the value of the header is not
1633 * recognized. If <b>reason</b> is provided, strdup the reason string
1634 * into it.
1637 parse_http_response(const char *headers, int *code, time_t *date,
1638 compress_method_t *compression, char **reason)
1640 unsigned n1, n2;
1641 char datestr[RFC1123_TIME_LEN+1];
1642 smartlist_t *parsed_headers;
1643 tor_assert(headers);
1644 tor_assert(code);
1646 while (TOR_ISSPACE(*headers)) headers++; /* tolerate leading whitespace */
1648 if (tor_sscanf(headers, "HTTP/1.%u %u", &n1, &n2) < 2 ||
1649 (n1 != 0 && n1 != 1) ||
1650 (n2 < 100 || n2 >= 600)) {
1651 log_warn(LD_HTTP,"Failed to parse header %s",escaped(headers));
1652 return -1;
1654 *code = n2;
1656 parsed_headers = smartlist_new();
1657 smartlist_split_string(parsed_headers, headers, "\n",
1658 SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
1659 if (reason) {
1660 smartlist_t *status_line_elements = smartlist_new();
1661 tor_assert(smartlist_len(parsed_headers));
1662 smartlist_split_string(status_line_elements,
1663 smartlist_get(parsed_headers, 0),
1664 " ", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 3);
1665 tor_assert(smartlist_len(status_line_elements) <= 3);
1666 if (smartlist_len(status_line_elements) == 3) {
1667 *reason = smartlist_get(status_line_elements, 2);
1668 smartlist_set(status_line_elements, 2, NULL); /* Prevent free */
1670 SMARTLIST_FOREACH(status_line_elements, char *, cp, tor_free(cp));
1671 smartlist_free(status_line_elements);
1673 if (date) {
1674 *date = 0;
1675 SMARTLIST_FOREACH(parsed_headers, const char *, s,
1676 if (!strcmpstart(s, "Date: ")) {
1677 strlcpy(datestr, s+6, sizeof(datestr));
1678 /* This will do nothing on failure, so we don't need to check
1679 the result. We shouldn't warn, since there are many other valid
1680 date formats besides the one we use. */
1681 parse_rfc1123_time(datestr, date);
1682 break;
1685 if (compression) {
1686 const char *enc = NULL;
1687 SMARTLIST_FOREACH(parsed_headers, const char *, s,
1688 if (!strcmpstart(s, "Content-Encoding: ")) {
1689 enc = s+18; break;
1691 if (!enc || !strcmp(enc, "identity")) {
1692 *compression = NO_METHOD;
1693 } else if (!strcmp(enc, "deflate") || !strcmp(enc, "x-deflate")) {
1694 *compression = ZLIB_METHOD;
1695 } else if (!strcmp(enc, "gzip") || !strcmp(enc, "x-gzip")) {
1696 *compression = GZIP_METHOD;
1697 } else {
1698 log_info(LD_HTTP, "Unrecognized content encoding: %s. Trying to deal.",
1699 escaped(enc));
1700 *compression = UNKNOWN_METHOD;
1703 SMARTLIST_FOREACH(parsed_headers, char *, s, tor_free(s));
1704 smartlist_free(parsed_headers);
1706 return 0;
1709 /** Return true iff <b>body</b> doesn't start with a plausible router or
1710 * network-status or microdescriptor opening. This is a sign of possible
1711 * compression. */
1712 static int
1713 body_is_plausible(const char *body, size_t len, int purpose)
1715 int i;
1716 if (len == 0)
1717 return 1; /* empty bodies don't need decompression */
1718 if (len < 32)
1719 return 0;
1720 if (purpose == DIR_PURPOSE_FETCH_MICRODESC) {
1721 return (!strcmpstart(body,"onion-key"));
1723 if (1) {
1724 if (!strcmpstart(body,"router") ||
1725 !strcmpstart(body,"network-status"))
1726 return 1;
1727 for (i=0;i<32;++i) {
1728 if (!TOR_ISPRINT(body[i]) && !TOR_ISSPACE(body[i]))
1729 return 0;
1732 return 1;
1735 /** Called when we've just fetched a bunch of router descriptors in
1736 * <b>body</b>. The list <b>which</b>, if present, holds digests for
1737 * descriptors we requested: descriptor digests if <b>descriptor_digests</b>
1738 * is true, or identity digests otherwise. Parse the descriptors, validate
1739 * them, and annotate them as having purpose <b>purpose</b> and as having been
1740 * downloaded from <b>source</b>.
1742 * Return the number of routers actually added. */
1743 static int
1744 load_downloaded_routers(const char *body, smartlist_t *which,
1745 int descriptor_digests,
1746 int router_purpose,
1747 const char *source)
1749 char buf[256];
1750 char time_buf[ISO_TIME_LEN+1];
1751 int added = 0;
1752 int general = router_purpose == ROUTER_PURPOSE_GENERAL;
1753 format_iso_time(time_buf, time(NULL));
1754 tor_assert(source);
1756 if (tor_snprintf(buf, sizeof(buf),
1757 "@downloaded-at %s\n"
1758 "@source %s\n"
1759 "%s%s%s", time_buf, escaped(source),
1760 !general ? "@purpose " : "",
1761 !general ? router_purpose_to_string(router_purpose) : "",
1762 !general ? "\n" : "")<0)
1763 return added;
1765 added = router_load_routers_from_string(body, NULL, SAVED_NOWHERE, which,
1766 descriptor_digests, buf);
1767 if (added && general)
1768 control_event_bootstrap(BOOTSTRAP_STATUS_LOADING_DESCRIPTORS,
1769 count_loading_descriptors_progress());
1770 return added;
1773 /** We are a client, and we've finished reading the server's
1774 * response. Parse it and act appropriately.
1776 * If we're still happy with using this directory server in the future, return
1777 * 0. Otherwise return -1; and the caller should consider trying the request
1778 * again.
1780 * The caller will take care of marking the connection for close.
1782 static int
1783 connection_dir_client_reached_eof(dir_connection_t *conn)
1785 char *body;
1786 char *headers;
1787 char *reason = NULL;
1788 size_t body_len = 0, orig_len = 0;
1789 int status_code;
1790 time_t date_header = 0;
1791 long apparent_skew;
1792 compress_method_t compression;
1793 int plausible;
1794 int skewed = 0;
1795 int allow_partial = (conn->base_.purpose == DIR_PURPOSE_FETCH_SERVERDESC ||
1796 conn->base_.purpose == DIR_PURPOSE_FETCH_EXTRAINFO ||
1797 conn->base_.purpose == DIR_PURPOSE_FETCH_MICRODESC);
1798 int was_compressed = 0;
1799 time_t now = time(NULL);
1800 int src_code;
1802 switch (connection_fetch_from_buf_http(TO_CONN(conn),
1803 &headers, MAX_HEADERS_SIZE,
1804 &body, &body_len, MAX_DIR_DL_SIZE,
1805 allow_partial)) {
1806 case -1: /* overflow */
1807 log_warn(LD_PROTOCOL,
1808 "'fetch' response too large (server '%s:%d'). Closing.",
1809 conn->base_.address, conn->base_.port);
1810 return -1;
1811 case 0:
1812 log_info(LD_HTTP,
1813 "'fetch' response not all here, but we're at eof. Closing.");
1814 return -1;
1815 /* case 1, fall through */
1817 orig_len = body_len;
1819 if (parse_http_response(headers, &status_code, &date_header,
1820 &compression, &reason) < 0) {
1821 log_warn(LD_HTTP,"Unparseable headers (server '%s:%d'). Closing.",
1822 conn->base_.address, conn->base_.port);
1823 tor_free(body); tor_free(headers);
1824 return -1;
1826 if (!reason) reason = tor_strdup("[no reason given]");
1828 log_debug(LD_DIR,
1829 "Received response from directory server '%s:%d': %d %s "
1830 "(purpose: %d)",
1831 conn->base_.address, conn->base_.port, status_code,
1832 escaped(reason),
1833 conn->base_.purpose);
1835 /* now check if it's got any hints for us about our IP address. */
1836 if (conn->dirconn_direct) {
1837 char *guess = http_get_header(headers, X_ADDRESS_HEADER);
1838 if (guess) {
1839 router_new_address_suggestion(guess, conn);
1840 tor_free(guess);
1844 if (date_header > 0) {
1845 /* The date header was written very soon after we sent our request,
1846 * so compute the skew as the difference between sending the request
1847 * and the date header. (We used to check now-date_header, but that's
1848 * inaccurate if we spend a lot of time downloading.)
1850 apparent_skew = conn->base_.timestamp_lastwritten - date_header;
1851 if (labs(apparent_skew)>ALLOW_DIRECTORY_TIME_SKEW) {
1852 int trusted = router_digest_is_trusted_dir(conn->identity_digest);
1853 clock_skew_warning(TO_CONN(conn), apparent_skew, trusted, LD_HTTP,
1854 "directory", "DIRSERV");
1855 skewed = 1; /* don't check the recommended-versions line */
1856 } else {
1857 log_debug(LD_HTTP, "Time on received directory is within tolerance; "
1858 "we are %ld seconds skewed. (That's okay.)", apparent_skew);
1861 (void) skewed; /* skewed isn't used yet. */
1863 if (status_code == 503) {
1864 routerstatus_t *rs;
1865 dir_server_t *ds;
1866 const char *id_digest = conn->identity_digest;
1867 log_info(LD_DIR,"Received http status code %d (%s) from server "
1868 "'%s:%d'. I'll try again soon.",
1869 status_code, escaped(reason), conn->base_.address,
1870 conn->base_.port);
1871 if ((rs = router_get_mutable_consensus_status_by_id(id_digest)))
1872 rs->last_dir_503_at = now;
1873 if ((ds = router_get_fallback_dirserver_by_digest(id_digest)))
1874 ds->fake_status.last_dir_503_at = now;
1876 tor_free(body); tor_free(headers); tor_free(reason);
1877 return -1;
1880 plausible = body_is_plausible(body, body_len, conn->base_.purpose);
1881 if (compression != NO_METHOD || !plausible) {
1882 char *new_body = NULL;
1883 size_t new_len = 0;
1884 compress_method_t guessed = detect_compression_method(body, body_len);
1885 if (compression == UNKNOWN_METHOD || guessed != compression) {
1886 /* Tell the user if we don't believe what we're told about compression.*/
1887 const char *description1, *description2;
1888 if (compression == ZLIB_METHOD)
1889 description1 = "as deflated";
1890 else if (compression == GZIP_METHOD)
1891 description1 = "as gzipped";
1892 else if (compression == NO_METHOD)
1893 description1 = "as uncompressed";
1894 else
1895 description1 = "with an unknown Content-Encoding";
1896 if (guessed == ZLIB_METHOD)
1897 description2 = "deflated";
1898 else if (guessed == GZIP_METHOD)
1899 description2 = "gzipped";
1900 else if (!plausible)
1901 description2 = "confusing binary junk";
1902 else
1903 description2 = "uncompressed";
1905 log_info(LD_HTTP, "HTTP body from server '%s:%d' was labeled %s, "
1906 "but it seems to be %s.%s",
1907 conn->base_.address, conn->base_.port, description1,
1908 description2,
1909 (compression>0 && guessed>0)?" Trying both.":"");
1911 /* Try declared compression first if we can. */
1912 if (compression == GZIP_METHOD || compression == ZLIB_METHOD)
1913 tor_gzip_uncompress(&new_body, &new_len, body, body_len, compression,
1914 !allow_partial, LOG_PROTOCOL_WARN);
1915 /* Okay, if that didn't work, and we think that it was compressed
1916 * differently, try that. */
1917 if (!new_body &&
1918 (guessed == GZIP_METHOD || guessed == ZLIB_METHOD) &&
1919 compression != guessed)
1920 tor_gzip_uncompress(&new_body, &new_len, body, body_len, guessed,
1921 !allow_partial, LOG_PROTOCOL_WARN);
1922 /* If we're pretty sure that we have a compressed directory, and
1923 * we didn't manage to uncompress it, then warn and bail. */
1924 if (!plausible && !new_body) {
1925 log_fn(LOG_PROTOCOL_WARN, LD_HTTP,
1926 "Unable to decompress HTTP body (server '%s:%d').",
1927 conn->base_.address, conn->base_.port);
1928 tor_free(body); tor_free(headers); tor_free(reason);
1929 return -1;
1931 if (new_body) {
1932 tor_free(body);
1933 body = new_body;
1934 body_len = new_len;
1935 was_compressed = 1;
1939 if (conn->base_.purpose == DIR_PURPOSE_FETCH_CONSENSUS) {
1940 int r;
1941 const char *flavname = conn->requested_resource;
1942 if (status_code != 200) {
1943 int severity = (status_code == 304) ? LOG_INFO : LOG_WARN;
1944 tor_log(severity, LD_DIR,
1945 "Received http status code %d (%s) from server "
1946 "'%s:%d' while fetching consensus directory.",
1947 status_code, escaped(reason), conn->base_.address,
1948 conn->base_.port);
1949 tor_free(body); tor_free(headers); tor_free(reason);
1950 networkstatus_consensus_download_failed(status_code, flavname);
1951 return -1;
1953 log_info(LD_DIR,"Received consensus directory (size %d) from server "
1954 "'%s:%d'", (int)body_len, conn->base_.address, conn->base_.port);
1955 if ((r=networkstatus_set_current_consensus(body, flavname, 0))<0) {
1956 log_fn(r<-1?LOG_WARN:LOG_INFO, LD_DIR,
1957 "Unable to load %s consensus directory downloaded from "
1958 "server '%s:%d'. I'll try again soon.",
1959 flavname, conn->base_.address, conn->base_.port);
1960 tor_free(body); tor_free(headers); tor_free(reason);
1961 networkstatus_consensus_download_failed(0, flavname);
1962 return -1;
1964 /* launches router downloads as needed */
1965 routers_update_all_from_networkstatus(now, 3);
1966 update_microdescs_from_networkstatus(now);
1967 update_microdesc_downloads(now);
1968 directory_info_has_arrived(now, 0, 0);
1969 log_info(LD_DIR, "Successfully loaded consensus.");
1972 if (conn->base_.purpose == DIR_PURPOSE_FETCH_CERTIFICATE) {
1973 if (status_code != 200) {
1974 log_warn(LD_DIR,
1975 "Received http status code %d (%s) from server "
1976 "'%s:%d' while fetching \"/tor/keys/%s\".",
1977 status_code, escaped(reason), conn->base_.address,
1978 conn->base_.port, conn->requested_resource);
1979 connection_dir_download_cert_failed(conn, status_code);
1980 tor_free(body); tor_free(headers); tor_free(reason);
1981 return -1;
1983 log_info(LD_DIR,"Received authority certificates (size %d) from server "
1984 "'%s:%d'", (int)body_len, conn->base_.address, conn->base_.port);
1987 * Tell trusted_dirs_load_certs_from_string() whether it was by fp
1988 * or fp-sk pair.
1990 src_code = -1;
1991 if (!strcmpstart(conn->requested_resource, "fp/")) {
1992 src_code = TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_DIGEST;
1993 } else if (!strcmpstart(conn->requested_resource, "fp-sk/")) {
1994 src_code = TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_SK_DIGEST;
1997 if (src_code != -1) {
1998 if (trusted_dirs_load_certs_from_string(body, src_code, 1)<0) {
1999 log_warn(LD_DIR, "Unable to parse fetched certificates");
2000 /* if we fetched more than one and only some failed, the successful
2001 * ones got flushed to disk so it's safe to call this on them */
2002 connection_dir_download_cert_failed(conn, status_code);
2003 } else {
2004 directory_info_has_arrived(now, 0, 0);
2005 log_info(LD_DIR, "Successfully loaded certificates from fetch.");
2007 } else {
2008 log_warn(LD_DIR,
2009 "Couldn't figure out what to do with fetched certificates for "
2010 "unknown resource %s",
2011 conn->requested_resource);
2012 connection_dir_download_cert_failed(conn, status_code);
2015 if (conn->base_.purpose == DIR_PURPOSE_FETCH_STATUS_VOTE) {
2016 const char *msg;
2017 int st;
2018 log_info(LD_DIR,"Got votes (size %d) from server %s:%d",
2019 (int)body_len, conn->base_.address, conn->base_.port);
2020 if (status_code != 200) {
2021 log_warn(LD_DIR,
2022 "Received http status code %d (%s) from server "
2023 "'%s:%d' while fetching \"/tor/status-vote/next/%s.z\".",
2024 status_code, escaped(reason), conn->base_.address,
2025 conn->base_.port, conn->requested_resource);
2026 tor_free(body); tor_free(headers); tor_free(reason);
2027 return -1;
2029 dirvote_add_vote(body, &msg, &st);
2030 if (st > 299) {
2031 log_warn(LD_DIR, "Error adding retrieved vote: %s", msg);
2032 } else {
2033 log_info(LD_DIR, "Added vote(s) successfully [msg: %s]", msg);
2036 if (conn->base_.purpose == DIR_PURPOSE_FETCH_DETACHED_SIGNATURES) {
2037 const char *msg = NULL;
2038 log_info(LD_DIR,"Got detached signatures (size %d) from server %s:%d",
2039 (int)body_len, conn->base_.address, conn->base_.port);
2040 if (status_code != 200) {
2041 log_warn(LD_DIR,
2042 "Received http status code %d (%s) from server '%s:%d' while fetching "
2043 "\"/tor/status-vote/next/consensus-signatures.z\".",
2044 status_code, escaped(reason), conn->base_.address,
2045 conn->base_.port);
2046 tor_free(body); tor_free(headers); tor_free(reason);
2047 return -1;
2049 if (dirvote_add_signatures(body, conn->base_.address, &msg)<0) {
2050 log_warn(LD_DIR, "Problem adding detached signatures from %s:%d: %s",
2051 conn->base_.address, conn->base_.port, msg?msg:"???");
2055 if (conn->base_.purpose == DIR_PURPOSE_FETCH_SERVERDESC ||
2056 conn->base_.purpose == DIR_PURPOSE_FETCH_EXTRAINFO) {
2057 int was_ei = conn->base_.purpose == DIR_PURPOSE_FETCH_EXTRAINFO;
2058 smartlist_t *which = NULL;
2059 int n_asked_for = 0;
2060 int descriptor_digests = conn->requested_resource &&
2061 !strcmpstart(conn->requested_resource,"d/");
2062 log_info(LD_DIR,"Received %s (size %d) from server '%s:%d'",
2063 was_ei ? "extra server info" : "server info",
2064 (int)body_len, conn->base_.address, conn->base_.port);
2065 if (conn->requested_resource &&
2066 (!strcmpstart(conn->requested_resource,"d/") ||
2067 !strcmpstart(conn->requested_resource,"fp/"))) {
2068 which = smartlist_new();
2069 dir_split_resource_into_fingerprints(conn->requested_resource +
2070 (descriptor_digests ? 2 : 3),
2071 which, NULL, 0);
2072 n_asked_for = smartlist_len(which);
2074 if (status_code != 200) {
2075 int dir_okay = status_code == 404 ||
2076 (status_code == 400 && !strcmp(reason, "Servers unavailable."));
2077 /* 404 means that it didn't have them; no big deal.
2078 * Older (pre-0.1.1.8) servers said 400 Servers unavailable instead. */
2079 log_fn(dir_okay ? LOG_INFO : LOG_WARN, LD_DIR,
2080 "Received http status code %d (%s) from server '%s:%d' "
2081 "while fetching \"/tor/server/%s\". I'll try again soon.",
2082 status_code, escaped(reason), conn->base_.address,
2083 conn->base_.port, conn->requested_resource);
2084 if (!which) {
2085 connection_dir_download_routerdesc_failed(conn);
2086 } else {
2087 dir_routerdesc_download_failed(which, status_code,
2088 conn->router_purpose,
2089 was_ei, descriptor_digests);
2090 SMARTLIST_FOREACH(which, char *, cp, tor_free(cp));
2091 smartlist_free(which);
2093 tor_free(body); tor_free(headers); tor_free(reason);
2094 return dir_okay ? 0 : -1;
2096 /* Learn the routers, assuming we requested by fingerprint or "all"
2097 * or "authority".
2099 * We use "authority" to fetch our own descriptor for
2100 * testing, and to fetch bridge descriptors for bootstrapping. Ignore
2101 * the output of "authority" requests unless we are using bridges,
2102 * since otherwise they'll be the response from reachability tests,
2103 * and we don't really want to add that to our routerlist. */
2104 if (which || (conn->requested_resource &&
2105 (!strcmpstart(conn->requested_resource, "all") ||
2106 (!strcmpstart(conn->requested_resource, "authority") &&
2107 get_options()->UseBridges)))) {
2108 /* as we learn from them, we remove them from 'which' */
2109 if (was_ei) {
2110 router_load_extrainfo_from_string(body, NULL, SAVED_NOWHERE, which,
2111 descriptor_digests);
2112 } else {
2113 //router_load_routers_from_string(body, NULL, SAVED_NOWHERE, which,
2114 // descriptor_digests, conn->router_purpose);
2115 if (load_downloaded_routers(body, which, descriptor_digests,
2116 conn->router_purpose,
2117 conn->base_.address))
2118 directory_info_has_arrived(now, 0, 0);
2121 if (which) { /* mark remaining ones as failed */
2122 log_info(LD_DIR, "Received %d/%d %s requested from %s:%d",
2123 n_asked_for-smartlist_len(which), n_asked_for,
2124 was_ei ? "extra-info documents" : "router descriptors",
2125 conn->base_.address, (int)conn->base_.port);
2126 if (smartlist_len(which)) {
2127 dir_routerdesc_download_failed(which, status_code,
2128 conn->router_purpose,
2129 was_ei, descriptor_digests);
2131 SMARTLIST_FOREACH(which, char *, cp, tor_free(cp));
2132 smartlist_free(which);
2134 if (directory_conn_is_self_reachability_test(conn))
2135 router_dirport_found_reachable();
2137 if (conn->base_.purpose == DIR_PURPOSE_FETCH_MICRODESC) {
2138 smartlist_t *which = NULL;
2139 log_info(LD_DIR,"Received answer to microdescriptor request (status %d, "
2140 "size %d) from server '%s:%d'",
2141 status_code, (int)body_len, conn->base_.address,
2142 conn->base_.port);
2143 tor_assert(conn->requested_resource &&
2144 !strcmpstart(conn->requested_resource, "d/"));
2145 which = smartlist_new();
2146 dir_split_resource_into_fingerprints(conn->requested_resource+2,
2147 which, NULL,
2148 DSR_DIGEST256|DSR_BASE64);
2149 if (status_code != 200) {
2150 log_info(LD_DIR, "Received status code %d (%s) from server "
2151 "'%s:%d' while fetching \"/tor/micro/%s\". I'll try again "
2152 "soon.",
2153 status_code, escaped(reason), conn->base_.address,
2154 (int)conn->base_.port, conn->requested_resource);
2155 dir_microdesc_download_failed(which, status_code);
2156 SMARTLIST_FOREACH(which, char *, cp, tor_free(cp));
2157 smartlist_free(which);
2158 tor_free(body); tor_free(headers); tor_free(reason);
2159 return 0;
2160 } else {
2161 smartlist_t *mds;
2162 mds = microdescs_add_to_cache(get_microdesc_cache(),
2163 body, body+body_len, SAVED_NOWHERE, 0,
2164 now, which);
2165 if (smartlist_len(which)) {
2166 /* Mark remaining ones as failed. */
2167 dir_microdesc_download_failed(which, status_code);
2169 if (mds && smartlist_len(mds)) {
2170 control_event_bootstrap(BOOTSTRAP_STATUS_LOADING_DESCRIPTORS,
2171 count_loading_descriptors_progress());
2172 directory_info_has_arrived(now, 0, 1);
2174 SMARTLIST_FOREACH(which, char *, cp, tor_free(cp));
2175 smartlist_free(which);
2176 smartlist_free(mds);
2180 if (conn->base_.purpose == DIR_PURPOSE_UPLOAD_DIR) {
2181 switch (status_code) {
2182 case 200: {
2183 dir_server_t *ds =
2184 router_get_trusteddirserver_by_digest(conn->identity_digest);
2185 char *rejected_hdr = http_get_header(headers,
2186 "X-Descriptor-Not-New: ");
2187 if (rejected_hdr) {
2188 if (!strcmp(rejected_hdr, "Yes")) {
2189 log_info(LD_GENERAL,
2190 "Authority '%s' declined our descriptor (not new)",
2191 ds->nickname);
2192 /* XXXX use this information; be sure to upload next one
2193 * sooner. -NM */
2194 /* XXXX023 On further thought, the task above implies that we're
2195 * basing our regenerate-descriptor time on when we uploaded the
2196 * last descriptor, not on the published time of the last
2197 * descriptor. If those are different, that's a bad thing to
2198 * do. -NM */
2200 tor_free(rejected_hdr);
2202 log_info(LD_GENERAL,"eof (status 200) after uploading server "
2203 "descriptor: finished.");
2204 control_event_server_status(
2205 LOG_NOTICE, "ACCEPTED_SERVER_DESCRIPTOR DIRAUTH=%s:%d",
2206 conn->base_.address, conn->base_.port);
2208 ds->has_accepted_serverdesc = 1;
2209 if (directories_have_accepted_server_descriptor())
2210 control_event_server_status(LOG_NOTICE, "GOOD_SERVER_DESCRIPTOR");
2212 break;
2213 case 400:
2214 log_warn(LD_GENERAL,"http status 400 (%s) response from "
2215 "dirserver '%s:%d'. Please correct.",
2216 escaped(reason), conn->base_.address, conn->base_.port);
2217 control_event_server_status(LOG_WARN,
2218 "BAD_SERVER_DESCRIPTOR DIRAUTH=%s:%d REASON=\"%s\"",
2219 conn->base_.address, conn->base_.port, escaped(reason));
2220 break;
2221 default:
2222 log_warn(LD_GENERAL,
2223 "http status %d (%s) reason unexpected while uploading "
2224 "descriptor to server '%s:%d').",
2225 status_code, escaped(reason), conn->base_.address,
2226 conn->base_.port);
2227 break;
2229 /* return 0 in all cases, since we don't want to mark any
2230 * dirservers down just because they don't like us. */
2233 if (conn->base_.purpose == DIR_PURPOSE_UPLOAD_VOTE) {
2234 switch (status_code) {
2235 case 200: {
2236 log_notice(LD_DIR,"Uploaded a vote to dirserver %s:%d",
2237 conn->base_.address, conn->base_.port);
2239 break;
2240 case 400:
2241 log_warn(LD_DIR,"http status 400 (%s) response after uploading "
2242 "vote to dirserver '%s:%d'. Please correct.",
2243 escaped(reason), conn->base_.address, conn->base_.port);
2244 break;
2245 default:
2246 log_warn(LD_GENERAL,
2247 "http status %d (%s) reason unexpected while uploading "
2248 "vote to server '%s:%d').",
2249 status_code, escaped(reason), conn->base_.address,
2250 conn->base_.port);
2251 break;
2253 /* return 0 in all cases, since we don't want to mark any
2254 * dirservers down just because they don't like us. */
2257 if (conn->base_.purpose == DIR_PURPOSE_UPLOAD_SIGNATURES) {
2258 switch (status_code) {
2259 case 200: {
2260 log_notice(LD_DIR,"Uploaded signature(s) to dirserver %s:%d",
2261 conn->base_.address, conn->base_.port);
2263 break;
2264 case 400:
2265 log_warn(LD_DIR,"http status 400 (%s) response after uploading "
2266 "signatures to dirserver '%s:%d'. Please correct.",
2267 escaped(reason), conn->base_.address, conn->base_.port);
2268 break;
2269 default:
2270 log_warn(LD_GENERAL,
2271 "http status %d (%s) reason unexpected while uploading "
2272 "signatures to server '%s:%d').",
2273 status_code, escaped(reason), conn->base_.address,
2274 conn->base_.port);
2275 break;
2277 /* return 0 in all cases, since we don't want to mark any
2278 * dirservers down just because they don't like us. */
2281 if (conn->base_.purpose == DIR_PURPOSE_FETCH_RENDDESC_V2) {
2282 #define SEND_HS_DESC_FAILED_EVENT(reason) ( \
2283 control_event_hs_descriptor_failed(conn->rend_data, \
2284 conn->identity_digest, \
2285 reason) )
2286 #define SEND_HS_DESC_FAILED_CONTENT() ( \
2287 control_event_hs_descriptor_content(conn->rend_data->onion_address, \
2288 conn->requested_resource, \
2289 conn->identity_digest, \
2290 NULL) )
2291 tor_assert(conn->rend_data);
2292 log_info(LD_REND,"Received rendezvous descriptor (size %d, status %d "
2293 "(%s))",
2294 (int)body_len, status_code, escaped(reason));
2295 switch (status_code) {
2296 case 200:
2298 rend_cache_entry_t *entry = NULL;
2300 switch (rend_cache_store_v2_desc_as_client(body,
2301 conn->requested_resource, conn->rend_data,
2302 &entry)) {
2303 case RCS_BADDESC:
2304 log_warn(LD_REND,"Fetching v2 rendezvous descriptor failed. "
2305 "Retrying at another directory.");
2306 /* We'll retry when connection_about_to_close_connection()
2307 * cleans this dir conn up. */
2308 SEND_HS_DESC_FAILED_EVENT("BAD_DESC");
2309 SEND_HS_DESC_FAILED_CONTENT();
2310 break;
2311 case RCS_OKAY:
2312 default:
2314 char service_id[REND_SERVICE_ID_LEN_BASE32 + 1];
2315 /* Should never be NULL here for an OKAY returned code. */
2316 tor_assert(entry);
2317 rend_get_service_id(entry->parsed->pk, service_id);
2319 /* success. notify pending connections about this. */
2320 log_info(LD_REND, "Successfully fetched v2 rendezvous "
2321 "descriptor.");
2322 control_event_hs_descriptor_received(service_id,
2323 conn->rend_data,
2324 conn->identity_digest);
2325 control_event_hs_descriptor_content(service_id,
2326 conn->requested_resource,
2327 conn->identity_digest,
2328 body);
2329 conn->base_.purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC_V2;
2330 rend_client_desc_trynow(service_id);
2331 memwipe(service_id, 0, sizeof(service_id));
2332 break;
2335 break;
2337 case 404:
2338 /* Not there. We'll retry when
2339 * connection_about_to_close_connection() cleans this conn up. */
2340 log_info(LD_REND,"Fetching v2 rendezvous descriptor failed: "
2341 "Retrying at another directory.");
2342 SEND_HS_DESC_FAILED_EVENT("NOT_FOUND");
2343 SEND_HS_DESC_FAILED_CONTENT();
2344 break;
2345 case 400:
2346 log_warn(LD_REND, "Fetching v2 rendezvous descriptor failed: "
2347 "http status 400 (%s). Dirserver didn't like our "
2348 "v2 rendezvous query? Retrying at another directory.",
2349 escaped(reason));
2350 SEND_HS_DESC_FAILED_EVENT("QUERY_REJECTED");
2351 SEND_HS_DESC_FAILED_CONTENT();
2352 break;
2353 default:
2354 log_warn(LD_REND, "Fetching v2 rendezvous descriptor failed: "
2355 "http status %d (%s) response unexpected while "
2356 "fetching v2 hidden service descriptor (server '%s:%d'). "
2357 "Retrying at another directory.",
2358 status_code, escaped(reason), conn->base_.address,
2359 conn->base_.port);
2360 SEND_HS_DESC_FAILED_EVENT("UNEXPECTED");
2361 SEND_HS_DESC_FAILED_CONTENT();
2362 break;
2366 if (conn->base_.purpose == DIR_PURPOSE_UPLOAD_RENDDESC_V2) {
2367 #define SEND_HS_DESC_UPLOAD_FAILED_EVENT(reason) ( \
2368 control_event_hs_descriptor_upload_failed( \
2369 conn->identity_digest, \
2370 conn->rend_data->onion_address, \
2371 reason) )
2372 log_info(LD_REND,"Uploaded rendezvous descriptor (status %d "
2373 "(%s))",
2374 status_code, escaped(reason));
2375 /* Without the rend data, we'll have a problem identifying what has been
2376 * uploaded for which service. */
2377 tor_assert(conn->rend_data);
2378 switch (status_code) {
2379 case 200:
2380 log_info(LD_REND,
2381 "Uploading rendezvous descriptor: finished with status "
2382 "200 (%s)", escaped(reason));
2383 control_event_hs_descriptor_uploaded(conn->identity_digest,
2384 conn->rend_data->onion_address);
2385 rend_service_desc_has_uploaded(conn->rend_data);
2386 break;
2387 case 400:
2388 log_warn(LD_REND,"http status 400 (%s) response from dirserver "
2389 "'%s:%d'. Malformed rendezvous descriptor?",
2390 escaped(reason), conn->base_.address, conn->base_.port);
2391 SEND_HS_DESC_UPLOAD_FAILED_EVENT("UPLOAD_REJECTED");
2392 break;
2393 default:
2394 log_warn(LD_REND,"http status %d (%s) response unexpected (server "
2395 "'%s:%d').",
2396 status_code, escaped(reason), conn->base_.address,
2397 conn->base_.port);
2398 SEND_HS_DESC_UPLOAD_FAILED_EVENT("UNEXPECTED");
2399 break;
2402 note_client_request(conn->base_.purpose, was_compressed, orig_len);
2403 tor_free(body); tor_free(headers); tor_free(reason);
2404 return 0;
2407 /** Called when a directory connection reaches EOF. */
2409 connection_dir_reached_eof(dir_connection_t *conn)
2411 int retval;
2412 if (conn->base_.state != DIR_CONN_STATE_CLIENT_READING) {
2413 log_info(LD_HTTP,"conn reached eof, not reading. [state=%d] Closing.",
2414 conn->base_.state);
2415 connection_close_immediate(TO_CONN(conn)); /* error: give up on flushing */
2416 connection_mark_for_close(TO_CONN(conn));
2417 return -1;
2420 retval = connection_dir_client_reached_eof(conn);
2421 if (retval == 0) /* success */
2422 conn->base_.state = DIR_CONN_STATE_CLIENT_FINISHED;
2423 connection_mark_for_close(TO_CONN(conn));
2424 return retval;
2427 /** If any directory object is arriving, and it's over 10MB large, we're
2428 * getting DoS'd. (As of 0.1.2.x, raw directories are about 1MB, and we never
2429 * ask for more than 96 router descriptors at a time.)
2431 #define MAX_DIRECTORY_OBJECT_SIZE (10*(1<<20))
2433 #define MAX_VOTE_DL_SIZE (MAX_DIRECTORY_OBJECT_SIZE * 5)
2435 /** Read handler for directory connections. (That's connections <em>to</em>
2436 * directory servers and connections <em>at</em> directory servers.)
2439 connection_dir_process_inbuf(dir_connection_t *conn)
2441 size_t max_size;
2442 tor_assert(conn);
2443 tor_assert(conn->base_.type == CONN_TYPE_DIR);
2445 /* Directory clients write, then read data until they receive EOF;
2446 * directory servers read data until they get an HTTP command, then
2447 * write their response (when it's finished flushing, they mark for
2448 * close).
2451 /* If we're on the dirserver side, look for a command. */
2452 if (conn->base_.state == DIR_CONN_STATE_SERVER_COMMAND_WAIT) {
2453 if (directory_handle_command(conn) < 0) {
2454 connection_mark_for_close(TO_CONN(conn));
2455 return -1;
2457 return 0;
2460 max_size =
2461 (TO_CONN(conn)->purpose == DIR_PURPOSE_FETCH_STATUS_VOTE) ?
2462 MAX_VOTE_DL_SIZE : MAX_DIRECTORY_OBJECT_SIZE;
2464 if (connection_get_inbuf_len(TO_CONN(conn)) > max_size) {
2465 log_warn(LD_HTTP,
2466 "Too much data received from directory connection (%s): "
2467 "denial of service attempt, or you need to upgrade?",
2468 conn->base_.address);
2469 connection_mark_for_close(TO_CONN(conn));
2470 return -1;
2473 if (!conn->base_.inbuf_reached_eof)
2474 log_debug(LD_HTTP,"Got data, not eof. Leaving on inbuf.");
2475 return 0;
2478 /** Called when we're about to finally unlink and free a directory connection:
2479 * perform necessary accounting and cleanup */
2480 void
2481 connection_dir_about_to_close(dir_connection_t *dir_conn)
2483 connection_t *conn = TO_CONN(dir_conn);
2485 if (conn->state < DIR_CONN_STATE_CLIENT_FINISHED) {
2486 /* It's a directory connection and connecting or fetching
2487 * failed: forget about this router, and maybe try again. */
2488 connection_dir_request_failed(dir_conn);
2490 /* If we were trying to fetch a v2 rend desc and did not succeed,
2491 * retry as needed. (If a fetch is successful, the connection state
2492 * is changed to DIR_PURPOSE_HAS_FETCHED_RENDDESC_V2 to mark that
2493 * refetching is unnecessary.) */
2494 if (conn->purpose == DIR_PURPOSE_FETCH_RENDDESC_V2 &&
2495 dir_conn->rend_data &&
2496 strlen(dir_conn->rend_data->onion_address) == REND_SERVICE_ID_LEN_BASE32)
2497 rend_client_refetch_v2_renddesc(dir_conn->rend_data);
2500 /** Create an http response for the client <b>conn</b> out of
2501 * <b>status</b> and <b>reason_phrase</b>. Write it to <b>conn</b>.
2503 static void
2504 write_http_status_line(dir_connection_t *conn, int status,
2505 const char *reason_phrase)
2507 char buf[256];
2508 if (tor_snprintf(buf, sizeof(buf), "HTTP/1.0 %d %s\r\n\r\n",
2509 status, reason_phrase ? reason_phrase : "OK") < 0) {
2510 log_warn(LD_BUG,"status line too long.");
2511 return;
2513 log_debug(LD_DIRSERV,"Wrote status 'HTTP/1.0 %d %s'", status, reason_phrase);
2514 connection_write_to_buf(buf, strlen(buf), TO_CONN(conn));
2517 /** Write the header for an HTTP/1.0 response onto <b>conn</b>-\>outbuf,
2518 * with <b>type</b> as the Content-Type.
2520 * If <b>length</b> is nonnegative, it is the Content-Length.
2521 * If <b>encoding</b> is provided, it is the Content-Encoding.
2522 * If <b>cache_lifetime</b> is greater than 0, the content may be cached for
2523 * up to cache_lifetime seconds. Otherwise, the content may not be cached. */
2524 static void
2525 write_http_response_header_impl(dir_connection_t *conn, ssize_t length,
2526 const char *type, const char *encoding,
2527 const char *extra_headers,
2528 long cache_lifetime)
2530 char date[RFC1123_TIME_LEN+1];
2531 char tmp[1024];
2532 char *cp;
2533 time_t now = time(NULL);
2535 tor_assert(conn);
2537 format_rfc1123_time(date, now);
2538 cp = tmp;
2539 tor_snprintf(cp, sizeof(tmp),
2540 "HTTP/1.0 200 OK\r\nDate: %s\r\n",
2541 date);
2542 cp += strlen(tmp);
2543 if (type) {
2544 tor_snprintf(cp, sizeof(tmp)-(cp-tmp), "Content-Type: %s\r\n", type);
2545 cp += strlen(cp);
2547 if (!is_local_addr(&conn->base_.addr)) {
2548 /* Don't report the source address for a nearby/private connection.
2549 * Otherwise we tend to mis-report in cases where incoming ports are
2550 * being forwarded to a Tor server running behind the firewall. */
2551 tor_snprintf(cp, sizeof(tmp)-(cp-tmp),
2552 X_ADDRESS_HEADER "%s\r\n", conn->base_.address);
2553 cp += strlen(cp);
2555 if (encoding) {
2556 tor_snprintf(cp, sizeof(tmp)-(cp-tmp),
2557 "Content-Encoding: %s\r\n", encoding);
2558 cp += strlen(cp);
2560 if (length >= 0) {
2561 tor_snprintf(cp, sizeof(tmp)-(cp-tmp),
2562 "Content-Length: %ld\r\n", (long)length);
2563 cp += strlen(cp);
2565 if (cache_lifetime > 0) {
2566 char expbuf[RFC1123_TIME_LEN+1];
2567 format_rfc1123_time(expbuf, (time_t)(now + cache_lifetime));
2568 /* We could say 'Cache-control: max-age=%d' here if we start doing
2569 * http/1.1 */
2570 tor_snprintf(cp, sizeof(tmp)-(cp-tmp),
2571 "Expires: %s\r\n", expbuf);
2572 cp += strlen(cp);
2573 } else if (cache_lifetime == 0) {
2574 /* We could say 'Cache-control: no-cache' here if we start doing
2575 * http/1.1 */
2576 strlcpy(cp, "Pragma: no-cache\r\n", sizeof(tmp)-(cp-tmp));
2577 cp += strlen(cp);
2579 if (extra_headers) {
2580 strlcpy(cp, extra_headers, sizeof(tmp)-(cp-tmp));
2581 cp += strlen(cp);
2583 if (sizeof(tmp)-(cp-tmp) > 3)
2584 memcpy(cp, "\r\n", 3);
2585 else
2586 tor_assert(0);
2587 connection_write_to_buf(tmp, strlen(tmp), TO_CONN(conn));
2590 /** As write_http_response_header_impl, but sets encoding and content-typed
2591 * based on whether the response will be <b>compressed</b> or not. */
2592 static void
2593 write_http_response_header(dir_connection_t *conn, ssize_t length,
2594 int compressed, long cache_lifetime)
2596 write_http_response_header_impl(conn, length,
2597 compressed?"application/octet-stream":"text/plain",
2598 compressed?"deflate":"identity",
2599 NULL,
2600 cache_lifetime);
2603 #if defined(INSTRUMENT_DOWNLOADS) || defined(RUNNING_DOXYGEN)
2604 /* DOCDOC */
2605 typedef struct request_t {
2606 uint64_t bytes; /**< How many bytes have we transferred? */
2607 uint64_t count; /**< How many requests have we made? */
2608 } request_t;
2610 /** Map used to keep track of how much data we've up/downloaded in what kind
2611 * of request. Maps from request type to pointer to request_t. */
2612 static strmap_t *request_map = NULL;
2614 /** Record that a client request of <b>purpose</b> was made, and that
2615 * <b>bytes</b> bytes of possibly <b>compressed</b> data were sent/received.
2616 * Used to keep track of how much we've up/downloaded in what kind of
2617 * request. */
2618 static void
2619 note_client_request(int purpose, int compressed, size_t bytes)
2621 char *key;
2622 const char *kind = NULL;
2623 switch (purpose) {
2624 case DIR_PURPOSE_FETCH_CONSENSUS: kind = "dl/consensus"; break;
2625 case DIR_PURPOSE_FETCH_CERTIFICATE: kind = "dl/cert"; break;
2626 case DIR_PURPOSE_FETCH_STATUS_VOTE: kind = "dl/vote"; break;
2627 case DIR_PURPOSE_FETCH_DETACHED_SIGNATURES: kind = "dl/detached_sig";
2628 break;
2629 case DIR_PURPOSE_FETCH_SERVERDESC: kind = "dl/server"; break;
2630 case DIR_PURPOSE_FETCH_EXTRAINFO: kind = "dl/extra"; break;
2631 case DIR_PURPOSE_UPLOAD_DIR: kind = "dl/ul-dir"; break;
2632 case DIR_PURPOSE_UPLOAD_VOTE: kind = "dl/ul-vote"; break;
2633 case DIR_PURPOSE_UPLOAD_SIGNATURES: kind = "dl/ul-sig"; break;
2634 case DIR_PURPOSE_FETCH_RENDDESC_V2: kind = "dl/rend2"; break;
2635 case DIR_PURPOSE_UPLOAD_RENDDESC_V2: kind = "dl/ul-rend2"; break;
2637 if (kind) {
2638 tor_asprintf(&key, "%s%s", kind, compressed?".z":"");
2639 } else {
2640 tor_asprintf(&key, "unknown purpose (%d)%s",
2641 purpose, compressed?".z":"");
2643 note_request(key, bytes);
2644 tor_free(key);
2647 /** Helper: initialize the request map to instrument downloads. */
2648 static void
2649 ensure_request_map_initialized(void)
2651 if (!request_map)
2652 request_map = strmap_new();
2655 /** Called when we just transmitted or received <b>bytes</b> worth of data
2656 * because of a request of type <b>key</b> (an arbitrary identifier): adds
2657 * <b>bytes</b> to the total associated with key. */
2658 void
2659 note_request(const char *key, size_t bytes)
2661 request_t *r;
2662 ensure_request_map_initialized();
2664 r = strmap_get(request_map, key);
2665 if (!r) {
2666 r = tor_malloc_zero(sizeof(request_t));
2667 strmap_set(request_map, key, r);
2669 r->bytes += bytes;
2670 r->count++;
2673 /** Return a newly allocated string holding a summary of bytes used per
2674 * request type. */
2675 char *
2676 directory_dump_request_log(void)
2678 smartlist_t *lines;
2679 char *result;
2680 strmap_iter_t *iter;
2682 ensure_request_map_initialized();
2684 lines = smartlist_new();
2686 for (iter = strmap_iter_init(request_map);
2687 !strmap_iter_done(iter);
2688 iter = strmap_iter_next(request_map, iter)) {
2689 const char *key;
2690 void *val;
2691 request_t *r;
2692 strmap_iter_get(iter, &key, &val);
2693 r = val;
2694 smartlist_add_asprintf(lines, "%s "U64_FORMAT" "U64_FORMAT"\n",
2695 key, U64_PRINTF_ARG(r->bytes), U64_PRINTF_ARG(r->count));
2697 smartlist_sort_strings(lines);
2698 result = smartlist_join_strings(lines, "", 0, NULL);
2699 SMARTLIST_FOREACH(lines, char *, cp, tor_free(cp));
2700 smartlist_free(lines);
2701 return result;
2703 #else
2704 static void
2705 note_client_request(int purpose, int compressed, size_t bytes)
2707 (void)purpose;
2708 (void)compressed;
2709 (void)bytes;
2712 void
2713 note_request(const char *key, size_t bytes)
2715 (void)key;
2716 (void)bytes;
2719 char *
2720 directory_dump_request_log(void)
2722 return tor_strdup("Not supported.");
2724 #endif
2726 /** Decide whether a client would accept the consensus we have.
2728 * Clients can say they only want a consensus if it's signed by more
2729 * than half the authorities in a list. They pass this list in
2730 * the url as "...consensus/<b>fpr</b>+<b>fpr</b>+<b>fpr</b>".
2732 * <b>fpr</b> may be an abbreviated fingerprint, i.e. only a left substring
2733 * of the full authority identity digest. (Only strings of even length,
2734 * i.e. encodings of full bytes, are handled correctly. In the case
2735 * of an odd number of hex digits the last one is silently ignored.)
2737 * Returns 1 if more than half of the requested authorities signed the
2738 * consensus, 0 otherwise.
2741 client_likes_consensus(networkstatus_t *v, const char *want_url)
2743 smartlist_t *want_authorities = smartlist_new();
2744 int need_at_least;
2745 int have = 0;
2747 dir_split_resource_into_fingerprints(want_url, want_authorities, NULL, 0);
2748 need_at_least = smartlist_len(want_authorities)/2+1;
2749 SMARTLIST_FOREACH_BEGIN(want_authorities, const char *, d) {
2750 char want_digest[DIGEST_LEN];
2751 size_t want_len = strlen(d)/2;
2752 if (want_len > DIGEST_LEN)
2753 want_len = DIGEST_LEN;
2755 if (base16_decode(want_digest, DIGEST_LEN, d, want_len*2) < 0) {
2756 log_fn(LOG_PROTOCOL_WARN, LD_DIR,
2757 "Failed to decode requested authority digest %s.", escaped(d));
2758 continue;
2761 SMARTLIST_FOREACH_BEGIN(v->voters, networkstatus_voter_info_t *, vi) {
2762 if (smartlist_len(vi->sigs) &&
2763 tor_memeq(vi->identity_digest, want_digest, want_len)) {
2764 have++;
2765 break;
2767 } SMARTLIST_FOREACH_END(vi);
2769 /* early exit, if we already have enough */
2770 if (have >= need_at_least)
2771 break;
2772 } SMARTLIST_FOREACH_END(d);
2774 SMARTLIST_FOREACH(want_authorities, char *, d, tor_free(d));
2775 smartlist_free(want_authorities);
2776 return (have >= need_at_least);
2779 /** Return the compression level we should use for sending a compressed
2780 * response of size <b>n_bytes</b>. */
2781 STATIC zlib_compression_level_t
2782 choose_compression_level(ssize_t n_bytes)
2784 if (! have_been_under_memory_pressure()) {
2785 return HIGH_COMPRESSION; /* we have plenty of RAM. */
2786 } else if (n_bytes < 0) {
2787 return HIGH_COMPRESSION; /* unknown; might be big. */
2788 } else if (n_bytes < 1024) {
2789 return LOW_COMPRESSION;
2790 } else if (n_bytes < 2048) {
2791 return MEDIUM_COMPRESSION;
2792 } else {
2793 return HIGH_COMPRESSION;
2797 /** Helper function: called when a dirserver gets a complete HTTP GET
2798 * request. Look for a request for a directory or for a rendezvous
2799 * service descriptor. On finding one, write a response into
2800 * conn-\>outbuf. If the request is unrecognized, send a 400.
2801 * Always return 0. */
2802 STATIC int
2803 directory_handle_command_get(dir_connection_t *conn, const char *headers,
2804 const char *req_body, size_t req_body_len)
2806 size_t dlen;
2807 char *url, *url_mem, *header;
2808 const or_options_t *options = get_options();
2809 time_t if_modified_since = 0;
2810 int compressed;
2811 size_t url_len;
2813 /* We ignore the body of a GET request. */
2814 (void)req_body;
2815 (void)req_body_len;
2817 log_debug(LD_DIRSERV,"Received GET command.");
2819 conn->base_.state = DIR_CONN_STATE_SERVER_WRITING;
2821 if (parse_http_url(headers, &url) < 0) {
2822 write_http_status_line(conn, 400, "Bad request");
2823 return 0;
2825 if ((header = http_get_header(headers, "If-Modified-Since: "))) {
2826 struct tm tm;
2827 if (parse_http_time(header, &tm) == 0) {
2828 if (tor_timegm(&tm, &if_modified_since)<0) {
2829 if_modified_since = 0;
2830 } else {
2831 log_debug(LD_DIRSERV, "If-Modified-Since is '%s'.", escaped(header));
2834 /* The correct behavior on a malformed If-Modified-Since header is to
2835 * act as if no If-Modified-Since header had been given. */
2836 tor_free(header);
2838 log_debug(LD_DIRSERV,"rewritten url as '%s'.", escaped(url));
2840 url_mem = url;
2841 url_len = strlen(url);
2842 compressed = url_len > 2 && !strcmp(url+url_len-2, ".z");
2843 if (compressed) {
2844 url[url_len-2] = '\0';
2845 url_len -= 2;
2848 if (!strcmp(url,"/tor/")) {
2849 const char *frontpage = get_dirportfrontpage();
2851 if (frontpage) {
2852 dlen = strlen(frontpage);
2853 /* Let's return a disclaimer page (users shouldn't use V1 anymore,
2854 and caches don't fetch '/', so this is safe). */
2856 /* [We don't check for write_bucket_low here, since we want to serve
2857 * this page no matter what.] */
2858 note_request(url, dlen);
2859 write_http_response_header_impl(conn, dlen, "text/html", "identity",
2860 NULL, DIRPORTFRONTPAGE_CACHE_LIFETIME);
2861 connection_write_to_buf(frontpage, dlen, TO_CONN(conn));
2862 goto done;
2864 /* if no disclaimer file, fall through and continue */
2867 if (!strcmpstart(url, "/tor/status-vote/current/consensus")) {
2868 /* v3 network status fetch. */
2869 smartlist_t *dir_fps = smartlist_new();
2870 const char *request_type = NULL;
2871 long lifetime = NETWORKSTATUS_CACHE_LIFETIME;
2873 if (1) {
2874 networkstatus_t *v;
2875 time_t now = time(NULL);
2876 const char *want_fps = NULL;
2877 char *flavor = NULL;
2878 int flav = FLAV_NS;
2879 #define CONSENSUS_URL_PREFIX "/tor/status-vote/current/consensus/"
2880 #define CONSENSUS_FLAVORED_PREFIX "/tor/status-vote/current/consensus-"
2881 /* figure out the flavor if any, and who we wanted to sign the thing */
2882 if (!strcmpstart(url, CONSENSUS_FLAVORED_PREFIX)) {
2883 const char *f, *cp;
2884 f = url + strlen(CONSENSUS_FLAVORED_PREFIX);
2885 cp = strchr(f, '/');
2886 if (cp) {
2887 want_fps = cp+1;
2888 flavor = tor_strndup(f, cp-f);
2889 } else {
2890 flavor = tor_strdup(f);
2892 flav = networkstatus_parse_flavor_name(flavor);
2893 if (flav < 0)
2894 flav = FLAV_NS;
2895 } else {
2896 if (!strcmpstart(url, CONSENSUS_URL_PREFIX))
2897 want_fps = url+strlen(CONSENSUS_URL_PREFIX);
2900 v = networkstatus_get_latest_consensus_by_flavor(flav);
2902 if (v && want_fps &&
2903 !client_likes_consensus(v, want_fps)) {
2904 write_http_status_line(conn, 404, "Consensus not signed by sufficient "
2905 "number of requested authorities");
2906 smartlist_free(dir_fps);
2907 geoip_note_ns_response(GEOIP_REJECT_NOT_ENOUGH_SIGS);
2908 tor_free(flavor);
2909 goto done;
2913 char *fp = tor_malloc_zero(DIGEST_LEN);
2914 if (flavor)
2915 strlcpy(fp, flavor, DIGEST_LEN);
2916 tor_free(flavor);
2917 smartlist_add(dir_fps, fp);
2919 request_type = compressed?"v3.z":"v3";
2920 lifetime = (v && v->fresh_until > now) ? v->fresh_until - now : 0;
2923 if (!smartlist_len(dir_fps)) { /* we failed to create/cache cp */
2924 write_http_status_line(conn, 503, "Network status object unavailable");
2925 smartlist_free(dir_fps);
2926 geoip_note_ns_response(GEOIP_REJECT_UNAVAILABLE);
2927 goto done;
2930 if (!dirserv_remove_old_statuses(dir_fps, if_modified_since)) {
2931 write_http_status_line(conn, 404, "Not found");
2932 SMARTLIST_FOREACH(dir_fps, char *, cp, tor_free(cp));
2933 smartlist_free(dir_fps);
2934 geoip_note_ns_response(GEOIP_REJECT_NOT_FOUND);
2935 goto done;
2936 } else if (!smartlist_len(dir_fps)) {
2937 write_http_status_line(conn, 304, "Not modified");
2938 SMARTLIST_FOREACH(dir_fps, char *, cp, tor_free(cp));
2939 smartlist_free(dir_fps);
2940 geoip_note_ns_response(GEOIP_REJECT_NOT_MODIFIED);
2941 goto done;
2944 dlen = dirserv_estimate_data_size(dir_fps, 0, compressed);
2945 if (global_write_bucket_low(TO_CONN(conn), dlen, 2)) {
2946 log_debug(LD_DIRSERV,
2947 "Client asked for network status lists, but we've been "
2948 "writing too many bytes lately. Sending 503 Dir busy.");
2949 write_http_status_line(conn, 503, "Directory busy, try again later");
2950 SMARTLIST_FOREACH(dir_fps, char *, fp, tor_free(fp));
2951 smartlist_free(dir_fps);
2953 geoip_note_ns_response(GEOIP_REJECT_BUSY);
2954 goto done;
2957 if (1) {
2958 struct in_addr in;
2959 tor_addr_t addr;
2960 if (tor_inet_aton((TO_CONN(conn))->address, &in)) {
2961 tor_addr_from_ipv4h(&addr, ntohl(in.s_addr));
2962 geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS,
2963 &addr, NULL,
2964 time(NULL));
2965 geoip_note_ns_response(GEOIP_SUCCESS);
2966 /* Note that a request for a network status has started, so that we
2967 * can measure the download time later on. */
2968 if (conn->dirreq_id)
2969 geoip_start_dirreq(conn->dirreq_id, dlen, DIRREQ_TUNNELED);
2970 else
2971 geoip_start_dirreq(TO_CONN(conn)->global_identifier, dlen,
2972 DIRREQ_DIRECT);
2976 // note_request(request_type,dlen);
2977 (void) request_type;
2978 write_http_response_header(conn, -1, compressed,
2979 smartlist_len(dir_fps) == 1 ? lifetime : 0);
2980 conn->fingerprint_stack = dir_fps;
2981 if (! compressed)
2982 conn->zlib_state = tor_zlib_new(0, ZLIB_METHOD, HIGH_COMPRESSION);
2984 /* Prime the connection with some data. */
2985 conn->dir_spool_src = DIR_SPOOL_NETWORKSTATUS;
2986 connection_dirserv_flushed_some(conn);
2987 goto done;
2990 if (!strcmpstart(url,"/tor/status-vote/current/") ||
2991 !strcmpstart(url,"/tor/status-vote/next/")) {
2992 /* XXXX If-modified-since is only implemented for the current
2993 * consensus: that's probably fine, since it's the only vote document
2994 * people fetch much. */
2995 int current;
2996 ssize_t body_len = 0;
2997 ssize_t estimated_len = 0;
2998 smartlist_t *items = smartlist_new();
2999 smartlist_t *dir_items = smartlist_new();
3000 int lifetime = 60; /* XXXX023 should actually use vote intervals. */
3001 url += strlen("/tor/status-vote/");
3002 current = !strcmpstart(url, "current/");
3003 url = strchr(url, '/');
3004 tor_assert(url);
3005 ++url;
3006 if (!strcmp(url, "consensus")) {
3007 const char *item;
3008 tor_assert(!current); /* we handle current consensus specially above,
3009 * since it wants to be spooled. */
3010 if ((item = dirvote_get_pending_consensus(FLAV_NS)))
3011 smartlist_add(items, (char*)item);
3012 } else if (!current && !strcmp(url, "consensus-signatures")) {
3013 /* XXXX the spec says that we should implement
3014 * current/consensus-signatures too. It doesn't seem to be needed,
3015 * though. */
3016 const char *item;
3017 if ((item=dirvote_get_pending_detached_signatures()))
3018 smartlist_add(items, (char*)item);
3019 } else if (!strcmp(url, "authority")) {
3020 const cached_dir_t *d;
3021 int flags = DGV_BY_ID |
3022 (current ? DGV_INCLUDE_PREVIOUS : DGV_INCLUDE_PENDING);
3023 if ((d=dirvote_get_vote(NULL, flags)))
3024 smartlist_add(dir_items, (cached_dir_t*)d);
3025 } else {
3026 const cached_dir_t *d;
3027 smartlist_t *fps = smartlist_new();
3028 int flags;
3029 if (!strcmpstart(url, "d/")) {
3030 url += 2;
3031 flags = DGV_INCLUDE_PENDING | DGV_INCLUDE_PREVIOUS;
3032 } else {
3033 flags = DGV_BY_ID |
3034 (current ? DGV_INCLUDE_PREVIOUS : DGV_INCLUDE_PENDING);
3036 dir_split_resource_into_fingerprints(url, fps, NULL,
3037 DSR_HEX|DSR_SORT_UNIQ);
3038 SMARTLIST_FOREACH(fps, char *, fp, {
3039 if ((d = dirvote_get_vote(fp, flags)))
3040 smartlist_add(dir_items, (cached_dir_t*)d);
3041 tor_free(fp);
3043 smartlist_free(fps);
3045 if (!smartlist_len(dir_items) && !smartlist_len(items)) {
3046 write_http_status_line(conn, 404, "Not found");
3047 goto vote_done;
3049 SMARTLIST_FOREACH(dir_items, cached_dir_t *, d,
3050 body_len += compressed ? d->dir_z_len : d->dir_len);
3051 estimated_len += body_len;
3052 SMARTLIST_FOREACH(items, const char *, item, {
3053 size_t ln = strlen(item);
3054 if (compressed) {
3055 estimated_len += ln/2;
3056 } else {
3057 body_len += ln; estimated_len += ln;
3061 if (global_write_bucket_low(TO_CONN(conn), estimated_len, 2)) {
3062 write_http_status_line(conn, 503, "Directory busy, try again later");
3063 goto vote_done;
3065 write_http_response_header(conn, body_len ? body_len : -1, compressed,
3066 lifetime);
3068 if (smartlist_len(items)) {
3069 if (compressed) {
3070 conn->zlib_state = tor_zlib_new(1, ZLIB_METHOD,
3071 choose_compression_level(estimated_len));
3072 SMARTLIST_FOREACH(items, const char *, c,
3073 connection_write_to_buf_zlib(c, strlen(c), conn, 0));
3074 connection_write_to_buf_zlib("", 0, conn, 1);
3075 } else {
3076 SMARTLIST_FOREACH(items, const char *, c,
3077 connection_write_to_buf(c, strlen(c), TO_CONN(conn)));
3079 } else {
3080 SMARTLIST_FOREACH(dir_items, cached_dir_t *, d,
3081 connection_write_to_buf(compressed ? d->dir_z : d->dir,
3082 compressed ? d->dir_z_len : d->dir_len,
3083 TO_CONN(conn)));
3085 vote_done:
3086 smartlist_free(items);
3087 smartlist_free(dir_items);
3088 goto done;
3091 if (!strcmpstart(url, "/tor/micro/d/")) {
3092 smartlist_t *fps = smartlist_new();
3094 dir_split_resource_into_fingerprints(url+strlen("/tor/micro/d/"),
3095 fps, NULL,
3096 DSR_DIGEST256|DSR_BASE64|DSR_SORT_UNIQ);
3098 if (!dirserv_have_any_microdesc(fps)) {
3099 write_http_status_line(conn, 404, "Not found");
3100 SMARTLIST_FOREACH(fps, char *, fp, tor_free(fp));
3101 smartlist_free(fps);
3102 goto done;
3104 dlen = dirserv_estimate_microdesc_size(fps, compressed);
3105 if (global_write_bucket_low(TO_CONN(conn), dlen, 2)) {
3106 log_info(LD_DIRSERV,
3107 "Client asked for server descriptors, but we've been "
3108 "writing too many bytes lately. Sending 503 Dir busy.");
3109 write_http_status_line(conn, 503, "Directory busy, try again later");
3110 SMARTLIST_FOREACH(fps, char *, fp, tor_free(fp));
3111 smartlist_free(fps);
3112 goto done;
3115 write_http_response_header(conn, -1, compressed, MICRODESC_CACHE_LIFETIME);
3116 conn->dir_spool_src = DIR_SPOOL_MICRODESC;
3117 conn->fingerprint_stack = fps;
3119 if (compressed)
3120 conn->zlib_state = tor_zlib_new(1, ZLIB_METHOD,
3121 choose_compression_level(dlen));
3123 connection_dirserv_flushed_some(conn);
3124 goto done;
3127 if (!strcmpstart(url,"/tor/server/") ||
3128 (!options->BridgeAuthoritativeDir &&
3129 !options->BridgeRelay && !strcmpstart(url,"/tor/extra/"))) {
3130 int res;
3131 const char *msg;
3132 const char *request_type = NULL;
3133 int cache_lifetime = 0;
3134 int is_extra = !strcmpstart(url,"/tor/extra/");
3135 url += is_extra ? strlen("/tor/extra/") : strlen("/tor/server/");
3136 conn->fingerprint_stack = smartlist_new();
3137 res = dirserv_get_routerdesc_fingerprints(conn->fingerprint_stack, url,
3138 &msg,
3139 !connection_dir_is_encrypted(conn),
3140 is_extra);
3142 if (!strcmpstart(url, "fp/")) {
3143 request_type = compressed?"/tor/server/fp.z":"/tor/server/fp";
3144 if (smartlist_len(conn->fingerprint_stack) == 1)
3145 cache_lifetime = ROUTERDESC_CACHE_LIFETIME;
3146 } else if (!strcmpstart(url, "authority")) {
3147 request_type = compressed?"/tor/server/authority.z":
3148 "/tor/server/authority";
3149 cache_lifetime = ROUTERDESC_CACHE_LIFETIME;
3150 } else if (!strcmpstart(url, "all")) {
3151 request_type = compressed?"/tor/server/all.z":"/tor/server/all";
3152 cache_lifetime = FULL_DIR_CACHE_LIFETIME;
3153 } else if (!strcmpstart(url, "d/")) {
3154 request_type = compressed?"/tor/server/d.z":"/tor/server/d";
3155 if (smartlist_len(conn->fingerprint_stack) == 1)
3156 cache_lifetime = ROUTERDESC_BY_DIGEST_CACHE_LIFETIME;
3157 } else {
3158 request_type = "/tor/server/?";
3160 (void) request_type; /* usable for note_request. */
3161 if (!strcmpstart(url, "d/"))
3162 conn->dir_spool_src =
3163 is_extra ? DIR_SPOOL_EXTRA_BY_DIGEST : DIR_SPOOL_SERVER_BY_DIGEST;
3164 else
3165 conn->dir_spool_src =
3166 is_extra ? DIR_SPOOL_EXTRA_BY_FP : DIR_SPOOL_SERVER_BY_FP;
3168 if (!dirserv_have_any_serverdesc(conn->fingerprint_stack,
3169 conn->dir_spool_src)) {
3170 res = -1;
3171 msg = "Not found";
3174 if (res < 0)
3175 write_http_status_line(conn, 404, msg);
3176 else {
3177 dlen = dirserv_estimate_data_size(conn->fingerprint_stack,
3178 1, compressed);
3179 if (global_write_bucket_low(TO_CONN(conn), dlen, 2)) {
3180 log_info(LD_DIRSERV,
3181 "Client asked for server descriptors, but we've been "
3182 "writing too many bytes lately. Sending 503 Dir busy.");
3183 write_http_status_line(conn, 503, "Directory busy, try again later");
3184 conn->dir_spool_src = DIR_SPOOL_NONE;
3185 goto done;
3187 write_http_response_header(conn, -1, compressed, cache_lifetime);
3188 if (compressed)
3189 conn->zlib_state = tor_zlib_new(1, ZLIB_METHOD,
3190 choose_compression_level(dlen));
3191 /* Prime the connection with some data. */
3192 connection_dirserv_flushed_some(conn);
3194 goto done;
3197 if (!strcmpstart(url,"/tor/keys/")) {
3198 smartlist_t *certs = smartlist_new();
3199 ssize_t len = -1;
3200 if (!strcmp(url, "/tor/keys/all")) {
3201 authority_cert_get_all(certs);
3202 } else if (!strcmp(url, "/tor/keys/authority")) {
3203 authority_cert_t *cert = get_my_v3_authority_cert();
3204 if (cert)
3205 smartlist_add(certs, cert);
3206 } else if (!strcmpstart(url, "/tor/keys/fp/")) {
3207 smartlist_t *fps = smartlist_new();
3208 dir_split_resource_into_fingerprints(url+strlen("/tor/keys/fp/"),
3209 fps, NULL,
3210 DSR_HEX|DSR_SORT_UNIQ);
3211 SMARTLIST_FOREACH(fps, char *, d, {
3212 authority_cert_t *c = authority_cert_get_newest_by_id(d);
3213 if (c) smartlist_add(certs, c);
3214 tor_free(d);
3216 smartlist_free(fps);
3217 } else if (!strcmpstart(url, "/tor/keys/sk/")) {
3218 smartlist_t *fps = smartlist_new();
3219 dir_split_resource_into_fingerprints(url+strlen("/tor/keys/sk/"),
3220 fps, NULL,
3221 DSR_HEX|DSR_SORT_UNIQ);
3222 SMARTLIST_FOREACH(fps, char *, d, {
3223 authority_cert_t *c = authority_cert_get_by_sk_digest(d);
3224 if (c) smartlist_add(certs, c);
3225 tor_free(d);
3227 smartlist_free(fps);
3228 } else if (!strcmpstart(url, "/tor/keys/fp-sk/")) {
3229 smartlist_t *fp_sks = smartlist_new();
3230 dir_split_resource_into_fingerprint_pairs(url+strlen("/tor/keys/fp-sk/"),
3231 fp_sks);
3232 SMARTLIST_FOREACH(fp_sks, fp_pair_t *, pair, {
3233 authority_cert_t *c = authority_cert_get_by_digests(pair->first,
3234 pair->second);
3235 if (c) smartlist_add(certs, c);
3236 tor_free(pair);
3238 smartlist_free(fp_sks);
3239 } else {
3240 write_http_status_line(conn, 400, "Bad request");
3241 goto keys_done;
3243 if (!smartlist_len(certs)) {
3244 write_http_status_line(conn, 404, "Not found");
3245 goto keys_done;
3247 SMARTLIST_FOREACH(certs, authority_cert_t *, c,
3248 if (c->cache_info.published_on < if_modified_since)
3249 SMARTLIST_DEL_CURRENT(certs, c));
3250 if (!smartlist_len(certs)) {
3251 write_http_status_line(conn, 304, "Not modified");
3252 goto keys_done;
3254 len = 0;
3255 SMARTLIST_FOREACH(certs, authority_cert_t *, c,
3256 len += c->cache_info.signed_descriptor_len);
3258 if (global_write_bucket_low(TO_CONN(conn), compressed?len/2:len, 2)) {
3259 write_http_status_line(conn, 503, "Directory busy, try again later");
3260 goto keys_done;
3263 write_http_response_header(conn, compressed?-1:len, compressed, 60*60);
3264 if (compressed) {
3265 conn->zlib_state = tor_zlib_new(1, ZLIB_METHOD,
3266 choose_compression_level(len));
3267 SMARTLIST_FOREACH(certs, authority_cert_t *, c,
3268 connection_write_to_buf_zlib(c->cache_info.signed_descriptor_body,
3269 c->cache_info.signed_descriptor_len,
3270 conn, 0));
3271 connection_write_to_buf_zlib("", 0, conn, 1);
3272 } else {
3273 SMARTLIST_FOREACH(certs, authority_cert_t *, c,
3274 connection_write_to_buf(c->cache_info.signed_descriptor_body,
3275 c->cache_info.signed_descriptor_len,
3276 TO_CONN(conn)));
3278 keys_done:
3279 smartlist_free(certs);
3280 goto done;
3283 if (connection_dir_is_encrypted(conn) &&
3284 !strcmpstart(url,"/tor/rendezvous2/")) {
3285 /* Handle v2 rendezvous descriptor fetch request. */
3286 const char *descp;
3287 const char *query = url + strlen("/tor/rendezvous2/");
3288 if (rend_valid_descriptor_id(query)) {
3289 log_info(LD_REND, "Got a v2 rendezvous descriptor request for ID '%s'",
3290 safe_str(escaped(query)));
3291 switch (rend_cache_lookup_v2_desc_as_dir(query, &descp)) {
3292 case 1: /* valid */
3293 write_http_response_header(conn, strlen(descp), 0, 0);
3294 connection_write_to_buf(descp, strlen(descp), TO_CONN(conn));
3295 break;
3296 case 0: /* well-formed but not present */
3297 write_http_status_line(conn, 404, "Not found");
3298 break;
3299 case -1: /* not well-formed */
3300 write_http_status_line(conn, 400, "Bad request");
3301 break;
3303 } else { /* not well-formed */
3304 write_http_status_line(conn, 400, "Bad request");
3306 goto done;
3309 if (options->BridgeAuthoritativeDir &&
3310 options->BridgePassword_AuthDigest_ &&
3311 connection_dir_is_encrypted(conn) &&
3312 !strcmp(url,"/tor/networkstatus-bridges")) {
3313 char *status;
3314 char digest[DIGEST256_LEN];
3316 header = http_get_header(headers, "Authorization: Basic ");
3317 if (header)
3318 crypto_digest256(digest, header, strlen(header), DIGEST_SHA256);
3320 /* now make sure the password is there and right */
3321 if (!header ||
3322 tor_memneq(digest,
3323 options->BridgePassword_AuthDigest_, DIGEST256_LEN)) {
3324 write_http_status_line(conn, 404, "Not found");
3325 tor_free(header);
3326 goto done;
3328 tor_free(header);
3330 /* all happy now. send an answer. */
3331 status = networkstatus_getinfo_by_purpose("bridge", time(NULL));
3332 dlen = strlen(status);
3333 write_http_response_header(conn, dlen, 0, 0);
3334 connection_write_to_buf(status, dlen, TO_CONN(conn));
3335 tor_free(status);
3336 goto done;
3339 if (!strcmpstart(url,"/tor/bytes.txt")) {
3340 char *bytes = directory_dump_request_log();
3341 size_t len = strlen(bytes);
3342 write_http_response_header(conn, len, 0, 0);
3343 connection_write_to_buf(bytes, len, TO_CONN(conn));
3344 tor_free(bytes);
3345 goto done;
3348 if (!strcmp(url,"/tor/robots.txt")) { /* /robots.txt will have been
3349 rewritten to /tor/robots.txt */
3350 char robots[] = "User-agent: *\r\nDisallow: /\r\n";
3351 size_t len = strlen(robots);
3352 write_http_response_header(conn, len, 0, ROBOTS_CACHE_LIFETIME);
3353 connection_write_to_buf(robots, len, TO_CONN(conn));
3354 goto done;
3357 #if defined(EXPORTMALLINFO) && defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO)
3358 #define ADD_MALLINFO_LINE(x) do { \
3359 smartlist_add_asprintf(lines, "%s %d\n", #x, mi.x); \
3360 }while(0);
3362 if (!strcmp(url,"/tor/mallinfo.txt") &&
3363 (tor_addr_eq_ipv4h(&conn->base_.addr, 0x7f000001ul))) {
3364 char *result;
3365 size_t len;
3366 struct mallinfo mi;
3367 smartlist_t *lines;
3369 memset(&mi, 0, sizeof(mi));
3370 mi = mallinfo();
3371 lines = smartlist_new();
3373 ADD_MALLINFO_LINE(arena)
3374 ADD_MALLINFO_LINE(ordblks)
3375 ADD_MALLINFO_LINE(smblks)
3376 ADD_MALLINFO_LINE(hblks)
3377 ADD_MALLINFO_LINE(hblkhd)
3378 ADD_MALLINFO_LINE(usmblks)
3379 ADD_MALLINFO_LINE(fsmblks)
3380 ADD_MALLINFO_LINE(uordblks)
3381 ADD_MALLINFO_LINE(fordblks)
3382 ADD_MALLINFO_LINE(keepcost)
3384 result = smartlist_join_strings(lines, "", 0, NULL);
3385 SMARTLIST_FOREACH(lines, char *, cp, tor_free(cp));
3386 smartlist_free(lines);
3388 len = strlen(result);
3389 write_http_response_header(conn, len, 0, 0);
3390 connection_write_to_buf(result, len, TO_CONN(conn));
3391 tor_free(result);
3392 goto done;
3394 #endif
3396 /* we didn't recognize the url */
3397 write_http_status_line(conn, 404, "Not found");
3399 done:
3400 tor_free(url_mem);
3401 return 0;
3404 /** Helper function: called when a dirserver gets a complete HTTP POST
3405 * request. Look for an uploaded server descriptor or rendezvous
3406 * service descriptor. On finding one, process it and write a
3407 * response into conn-\>outbuf. If the request is unrecognized, send a
3408 * 400. Always return 0. */
3409 static int
3410 directory_handle_command_post(dir_connection_t *conn, const char *headers,
3411 const char *body, size_t body_len)
3413 char *url = NULL;
3414 const or_options_t *options = get_options();
3416 log_debug(LD_DIRSERV,"Received POST command.");
3418 conn->base_.state = DIR_CONN_STATE_SERVER_WRITING;
3420 if (parse_http_url(headers, &url) < 0) {
3421 write_http_status_line(conn, 400, "Bad request");
3422 return 0;
3424 log_debug(LD_DIRSERV,"rewritten url as '%s'.", escaped(url));
3426 /* Handle v2 rendezvous service publish request. */
3427 if (connection_dir_is_encrypted(conn) &&
3428 !strcmpstart(url,"/tor/rendezvous2/publish")) {
3429 switch (rend_cache_store_v2_desc_as_dir(body)) {
3430 case RCS_BADDESC:
3431 log_warn(LD_REND, "Rejected v2 rend descriptor (length %d) from %s.",
3432 (int)body_len, conn->base_.address);
3433 write_http_status_line(conn, 400,
3434 "Invalid v2 service descriptor rejected");
3435 break;
3436 case RCS_OKAY:
3437 default:
3438 write_http_status_line(conn, 200, "Service descriptor (v2) stored");
3439 log_info(LD_REND, "Handled v2 rendezvous descriptor post: accepted");
3441 goto done;
3444 if (!authdir_mode(options)) {
3445 /* we just provide cached directories; we don't want to
3446 * receive anything. */
3447 write_http_status_line(conn, 400, "Nonauthoritative directory does not "
3448 "accept posted server descriptors");
3449 goto done;
3452 if (authdir_mode_handles_descs(options, -1) &&
3453 !strcmp(url,"/tor/")) { /* server descriptor post */
3454 const char *msg = "[None]";
3455 uint8_t purpose = authdir_mode_bridge(options) ?
3456 ROUTER_PURPOSE_BRIDGE : ROUTER_PURPOSE_GENERAL;
3457 was_router_added_t r = dirserv_add_multiple_descriptors(body, purpose,
3458 conn->base_.address, &msg);
3459 tor_assert(msg);
3461 if (r == ROUTER_ADDED_NOTIFY_GENERATOR) {
3462 /* Accepted with a message. */
3463 log_info(LD_DIRSERV,
3464 "Problematic router descriptor or extra-info from %s "
3465 "(\"%s\").",
3466 conn->base_.address, msg);
3467 write_http_status_line(conn, 400, msg);
3468 } else if (r == ROUTER_ADDED_SUCCESSFULLY) {
3469 write_http_status_line(conn, 200, msg);
3470 } else if (WRA_WAS_OUTDATED(r)) {
3471 write_http_response_header_impl(conn, -1, NULL, NULL,
3472 "X-Descriptor-Not-New: Yes\r\n", -1);
3473 } else {
3474 log_info(LD_DIRSERV,
3475 "Rejected router descriptor or extra-info from %s "
3476 "(\"%s\").",
3477 conn->base_.address, msg);
3478 write_http_status_line(conn, 400, msg);
3480 goto done;
3483 if (authdir_mode_v3(options) &&
3484 !strcmp(url,"/tor/post/vote")) { /* v3 networkstatus vote */
3485 const char *msg = "OK";
3486 int status;
3487 if (dirvote_add_vote(body, &msg, &status)) {
3488 write_http_status_line(conn, status, "Vote stored");
3489 } else {
3490 tor_assert(msg);
3491 log_warn(LD_DIRSERV, "Rejected vote from %s (\"%s\").",
3492 conn->base_.address, msg);
3493 write_http_status_line(conn, status, msg);
3495 goto done;
3498 if (authdir_mode_v3(options) &&
3499 !strcmp(url,"/tor/post/consensus-signature")) { /* sigs on consensus. */
3500 const char *msg = NULL;
3501 if (dirvote_add_signatures(body, conn->base_.address, &msg)>=0) {
3502 write_http_status_line(conn, 200, msg?msg:"Signatures stored");
3503 } else {
3504 log_warn(LD_DIR, "Unable to store signatures posted by %s: %s",
3505 conn->base_.address, msg?msg:"???");
3506 write_http_status_line(conn, 400, msg?msg:"Unable to store signatures");
3508 goto done;
3511 /* we didn't recognize the url */
3512 write_http_status_line(conn, 404, "Not found");
3514 done:
3515 tor_free(url);
3516 return 0;
3519 /** Called when a dirserver receives data on a directory connection;
3520 * looks for an HTTP request. If the request is complete, remove it
3521 * from the inbuf, try to process it; otherwise, leave it on the
3522 * buffer. Return a 0 on success, or -1 on error.
3524 static int
3525 directory_handle_command(dir_connection_t *conn)
3527 char *headers=NULL, *body=NULL;
3528 size_t body_len=0;
3529 int r;
3531 tor_assert(conn);
3532 tor_assert(conn->base_.type == CONN_TYPE_DIR);
3534 switch (connection_fetch_from_buf_http(TO_CONN(conn),
3535 &headers, MAX_HEADERS_SIZE,
3536 &body, &body_len, MAX_DIR_UL_SIZE, 0)) {
3537 case -1: /* overflow */
3538 log_warn(LD_DIRSERV,
3539 "Request too large from address '%s' to DirPort. Closing.",
3540 safe_str(conn->base_.address));
3541 return -1;
3542 case 0:
3543 log_debug(LD_DIRSERV,"command not all here yet.");
3544 return 0;
3545 /* case 1, fall through */
3548 http_set_address_origin(headers, TO_CONN(conn));
3549 // we should escape headers here as well,
3550 // but we can't call escaped() twice, as it uses the same buffer
3551 //log_debug(LD_DIRSERV,"headers %s, body %s.", headers, escaped(body));
3553 if (!strncasecmp(headers,"GET",3))
3554 r = directory_handle_command_get(conn, headers, body, body_len);
3555 else if (!strncasecmp(headers,"POST",4))
3556 r = directory_handle_command_post(conn, headers, body, body_len);
3557 else {
3558 log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
3559 "Got headers %s with unknown command. Closing.",
3560 escaped(headers));
3561 r = -1;
3564 tor_free(headers); tor_free(body);
3565 return r;
3568 /** Write handler for directory connections; called when all data has
3569 * been flushed. Close the connection or wait for a response as
3570 * appropriate.
3573 connection_dir_finished_flushing(dir_connection_t *conn)
3575 tor_assert(conn);
3576 tor_assert(conn->base_.type == CONN_TYPE_DIR);
3578 /* Note that we have finished writing the directory response. For direct
3579 * connections this means we're done; for tunneled connections it's only
3580 * an intermediate step. */
3581 if (conn->dirreq_id)
3582 geoip_change_dirreq_state(conn->dirreq_id, DIRREQ_TUNNELED,
3583 DIRREQ_FLUSHING_DIR_CONN_FINISHED);
3584 else
3585 geoip_change_dirreq_state(TO_CONN(conn)->global_identifier,
3586 DIRREQ_DIRECT,
3587 DIRREQ_FLUSHING_DIR_CONN_FINISHED);
3588 switch (conn->base_.state) {
3589 case DIR_CONN_STATE_CONNECTING:
3590 case DIR_CONN_STATE_CLIENT_SENDING:
3591 log_debug(LD_DIR,"client finished sending command.");
3592 conn->base_.state = DIR_CONN_STATE_CLIENT_READING;
3593 return 0;
3594 case DIR_CONN_STATE_SERVER_WRITING:
3595 if (conn->dir_spool_src != DIR_SPOOL_NONE) {
3596 #ifdef USE_BUFFEREVENTS
3597 /* This can happen with paired bufferevents, since a paired connection
3598 * can flush immediately when you write to it, making the subsequent
3599 * check in connection_handle_write_cb() decide that the connection
3600 * is flushed. */
3601 log_debug(LD_DIRSERV, "Emptied a dirserv buffer, but still spooling.");
3602 #else
3603 log_warn(LD_BUG, "Emptied a dirserv buffer, but it's still spooling!");
3604 connection_mark_for_close(TO_CONN(conn));
3605 #endif
3606 } else {
3607 log_debug(LD_DIRSERV, "Finished writing server response. Closing.");
3608 connection_mark_for_close(TO_CONN(conn));
3610 return 0;
3611 default:
3612 log_warn(LD_BUG,"called in unexpected state %d.",
3613 conn->base_.state);
3614 tor_fragile_assert();
3615 return -1;
3617 return 0;
3620 /* A helper function for connection_dir_close_consensus_conn_if_extra()
3621 * and connection_dir_close_extra_consensus_conns() that returns 0 if
3622 * we can't have, or don't want to close, excess consensus connections. */
3623 STATIC int
3624 connection_dir_would_close_consensus_conn_helper(void)
3626 const or_options_t *options = get_options();
3628 /* we're only interested in closing excess connections if we could
3629 * have created any in the first place */
3630 if (!networkstatus_consensus_can_use_multiple_directories(options)) {
3631 return 0;
3634 /* We want to close excess connections downloading a consensus.
3635 * If there aren't any excess, we don't have anything to close. */
3636 if (!networkstatus_consensus_has_excess_connections()) {
3637 return 0;
3640 /* If we have excess connections, but none of them are downloading a
3641 * consensus, and we are still bootstrapping (that is, we have no usable
3642 * consensus), we don't want to close any until one starts downloading. */
3643 if (!networkstatus_consensus_is_downloading_usable_flavor()
3644 && networkstatus_consensus_is_boostrapping(time(NULL))) {
3645 return 0;
3648 /* If we have just stopped bootstrapping (that is, just parsed a consensus),
3649 * we might still have some excess connections hanging around. So we still
3650 * have to check if we want to close any, even if we've stopped
3651 * bootstrapping. */
3652 return 1;
3655 /* Check if we would close excess consensus connections. If we would, any
3656 * new consensus connection would become excess immediately, so return 1.
3657 * Otherwise, return 0. */
3659 connection_dir_avoid_extra_connection_for_purpose(unsigned int purpose)
3661 const or_options_t *options = get_options();
3663 /* We're not interested in connections that aren't fetching a consensus. */
3664 if (purpose != DIR_PURPOSE_FETCH_CONSENSUS) {
3665 return 0;
3668 /* we're only interested in avoiding excess connections if we could
3669 * have created any in the first place */
3670 if (!networkstatus_consensus_can_use_multiple_directories(options)) {
3671 return 0;
3674 /* If there are connections downloading a consensus, and we are still
3675 * bootstrapping (that is, we have no usable consensus), we can be sure that
3676 * any further connections would be excess. */
3677 if (networkstatus_consensus_is_downloading_usable_flavor()
3678 && networkstatus_consensus_is_boostrapping(time(NULL))) {
3679 return 1;
3682 return 0;
3685 /* Check if we have excess consensus download connection attempts, and close
3686 * conn:
3687 * - if we don't have a consensus, and we're downloading a consensus, and conn
3688 * is not downloading a consensus yet, close it;
3689 * - if we do have a consensus, conn is excess, close it. */
3691 connection_dir_close_consensus_conn_if_extra(dir_connection_t *conn)
3693 tor_assert(conn);
3694 tor_assert(conn->base_.type == CONN_TYPE_DIR);
3696 /* We're not interested in connections that aren't fetching a consensus. */
3697 if (conn->base_.purpose != DIR_PURPOSE_FETCH_CONSENSUS) {
3698 return 0;
3701 /* The connection has already been closed */
3702 if (conn->base_.marked_for_close) {
3703 return 0;
3706 if (!connection_dir_would_close_consensus_conn_helper()) {
3707 return 0;
3710 const int we_are_bootstrapping = networkstatus_consensus_is_boostrapping(
3711 time(NULL));
3713 /* We don't want to check other connections to see if they are downloading,
3714 * as this is prone to race-conditions. So leave it for
3715 * connection_dir_consider_close_extra_consensus_conns() to clean up.
3717 * But if conn has just started connecting, or we have a consensus already,
3718 * we can be sure it's not needed any more. */
3719 if (!we_are_bootstrapping
3720 || conn->base_.state == DIR_CONN_STATE_CONNECTING) {
3721 connection_close_immediate(&conn->base_);
3722 connection_mark_for_close(&conn->base_);
3723 return -1;
3726 return 0;
3729 /* Check if we have excess consensus download connection attempts, and close
3730 * them:
3731 * - if we don't have a consensus, and we're downloading a consensus, keep an
3732 * earlier connection, or a connection to a fallback directory, and close
3733 * all other connections;
3734 * - if we do have a consensus, close all connections: they are all excess. */
3735 void
3736 connection_dir_close_extra_consensus_conns(void)
3738 if (!connection_dir_would_close_consensus_conn_helper()) {
3739 return;
3742 int we_are_bootstrapping = networkstatus_consensus_is_boostrapping(
3743 time(NULL));
3745 const char *usable_resource = networkstatus_get_flavor_name(
3746 usable_consensus_flavor());
3747 smartlist_t *consens_usable_conns =
3748 connection_dir_list_by_purpose_and_resource(
3749 DIR_PURPOSE_FETCH_CONSENSUS,
3750 usable_resource);
3752 /* If we want to keep a connection that's downloading, find a connection to
3753 * keep, favouring:
3754 * - connections opened earlier (they are likely to have progressed further)
3755 * - connections to fallbacks (to reduce the load on authorities) */
3756 dir_connection_t *kept_download_conn = NULL;
3757 int kept_is_authority = 0;
3758 if (we_are_bootstrapping) {
3759 SMARTLIST_FOREACH_BEGIN(consens_usable_conns,
3760 dir_connection_t *, d) {
3761 tor_assert(d);
3762 int d_is_authority = router_digest_is_trusted_dir(d->identity_digest);
3763 /* keep the first connection that is past the connecting state, but
3764 * prefer fallbacks. */
3765 if (d->base_.state != DIR_CONN_STATE_CONNECTING) {
3766 if (!kept_download_conn || (kept_is_authority && !d_is_authority)) {
3767 kept_download_conn = d;
3768 kept_is_authority = d_is_authority;
3769 /* we've found the earliest fallback, and want to keep it regardless
3770 * of any other connections */
3771 if (!kept_is_authority)
3772 break;
3775 } SMARTLIST_FOREACH_END(d);
3778 SMARTLIST_FOREACH_BEGIN(consens_usable_conns,
3779 dir_connection_t *, d) {
3780 tor_assert(d);
3781 /* don't close this connection if it's the one we want to keep */
3782 if (kept_download_conn && d == kept_download_conn)
3783 continue;
3784 /* mark all other connections for close */
3785 if (!d->base_.marked_for_close) {
3786 connection_close_immediate(&d->base_);
3787 connection_mark_for_close(&d->base_);
3789 } SMARTLIST_FOREACH_END(d);
3791 smartlist_free(consens_usable_conns);
3792 consens_usable_conns = NULL;
3794 /* make sure we've closed all excess connections */
3795 const int final_connecting_conn_count =
3796 connection_dir_count_by_purpose_resource_and_state(
3797 DIR_PURPOSE_FETCH_CONSENSUS,
3798 usable_resource,
3799 DIR_CONN_STATE_CONNECTING);
3800 if (final_connecting_conn_count > 0) {
3801 log_warn(LD_BUG, "Expected 0 consensus connections connecting after "
3802 "cleanup, got %d.", final_connecting_conn_count);
3804 const int expected_final_conn_count = (we_are_bootstrapping ? 1 : 0);
3805 const int final_conn_count =
3806 connection_dir_count_by_purpose_and_resource(
3807 DIR_PURPOSE_FETCH_CONSENSUS,
3808 usable_resource);
3809 if (final_conn_count > expected_final_conn_count) {
3810 log_warn(LD_BUG, "Expected %d consensus connections after cleanup, got "
3811 "%d.", expected_final_conn_count, final_connecting_conn_count);
3815 /** Connected handler for directory connections: begin sending data to the
3816 * server, and return 0, or, if the connection is an excess bootstrap
3817 * connection, close all excess bootstrap connections.
3818 * Only used when connections don't immediately connect. */
3820 connection_dir_finished_connecting(dir_connection_t *conn)
3822 tor_assert(conn);
3823 tor_assert(conn->base_.type == CONN_TYPE_DIR);
3824 tor_assert(conn->base_.state == DIR_CONN_STATE_CONNECTING);
3826 log_debug(LD_HTTP,"Dir connection to router %s:%u established.",
3827 conn->base_.address,conn->base_.port);
3829 if (connection_dir_close_consensus_conn_if_extra(conn)) {
3830 return -1;
3833 /* start flushing conn */
3834 conn->base_.state = DIR_CONN_STATE_CLIENT_SENDING;
3835 return 0;
3838 /** Decide which download schedule we want to use based on descriptor type
3839 * in <b>dls</b> and <b>options</b>.
3840 * Then return a list of int pointers defining download delays in seconds.
3841 * Helper function for download_status_increment_failure(),
3842 * download_status_reset(), and download_status_increment_attempt(). */
3843 STATIC const smartlist_t *
3844 find_dl_schedule(download_status_t *dls, const or_options_t *options)
3846 const int dir_server = dir_server_mode(options);
3847 const int multi_d = networkstatus_consensus_can_use_multiple_directories(
3848 options);
3849 const int we_are_bootstrapping = networkstatus_consensus_is_boostrapping(
3850 time(NULL));
3851 const int use_fallbacks = networkstatus_consensus_can_use_extra_fallbacks(
3852 options);
3853 switch (dls->schedule) {
3854 case DL_SCHED_GENERIC:
3855 if (dir_server) {
3856 return options->TestingServerDownloadSchedule;
3857 } else {
3858 return options->TestingClientDownloadSchedule;
3860 case DL_SCHED_CONSENSUS:
3861 if (!multi_d) {
3862 return options->TestingServerConsensusDownloadSchedule;
3863 } else {
3864 if (we_are_bootstrapping) {
3865 if (!use_fallbacks) {
3866 /* A bootstrapping client without extra fallback directories */
3867 return
3868 options->TestingClientBootstrapConsensusAuthorityOnlyDownloadSchedule;
3869 } else if (dls->want_authority) {
3870 /* A bootstrapping client with extra fallback directories, but
3871 * connecting to an authority */
3872 return
3873 options->TestingClientBootstrapConsensusAuthorityDownloadSchedule;
3874 } else {
3875 /* A bootstrapping client connecting to extra fallback directories
3877 return
3878 options->TestingClientBootstrapConsensusFallbackDownloadSchedule;
3880 } else {
3881 return options->TestingClientConsensusDownloadSchedule;
3884 case DL_SCHED_BRIDGE:
3885 return options->TestingBridgeDownloadSchedule;
3886 default:
3887 tor_assert(0);
3890 /* Impossible, but gcc will fail with -Werror without a `return`. */
3891 return NULL;
3894 /* Find the current delay for dls based on schedule.
3895 * Set dls->next_attempt_at based on now, and return the delay.
3896 * Helper for download_status_increment_failure and
3897 * download_status_increment_attempt. */
3898 STATIC int
3899 download_status_schedule_get_delay(download_status_t *dls,
3900 const smartlist_t *schedule,
3901 time_t now)
3903 tor_assert(dls);
3904 tor_assert(schedule);
3906 int delay = INT_MAX;
3907 uint8_t dls_schedule_position = (dls->increment_on
3908 == DL_SCHED_INCREMENT_ATTEMPT
3909 ? dls->n_download_attempts
3910 : dls->n_download_failures);
3912 if (dls_schedule_position < smartlist_len(schedule))
3913 delay = *(int *)smartlist_get(schedule, dls_schedule_position);
3914 else if (dls_schedule_position == IMPOSSIBLE_TO_DOWNLOAD)
3915 delay = INT_MAX;
3916 else
3917 delay = *(int *)smartlist_get(schedule, smartlist_len(schedule) - 1);
3919 /* A negative delay makes no sense. Knowing that delay is
3920 * non-negative allows us to safely do the wrapping check below. */
3921 tor_assert(delay >= 0);
3923 /* Avoid now+delay overflowing INT_MAX, by comparing with a subtraction
3924 * that won't overflow (since delay is non-negative). */
3925 if (delay < INT_MAX && now <= INT_MAX - delay) {
3926 dls->next_attempt_at = now+delay;
3927 } else {
3928 dls->next_attempt_at = TIME_MAX;
3931 return delay;
3934 /* Log a debug message about item, which increments on increment_action, has
3935 * incremented dls_n_download_increments times. The message varies based on
3936 * was_schedule_incremented (if not, not_incremented_response is logged), and
3937 * the values of increment, dls_next_attempt_at, and now.
3938 * Helper for download_status_increment_failure and
3939 * download_status_increment_attempt. */
3940 static void
3941 download_status_log_helper(const char *item, int was_schedule_incremented,
3942 const char *increment_action,
3943 const char *not_incremented_response,
3944 uint8_t dls_n_download_increments, int increment,
3945 time_t dls_next_attempt_at, time_t now)
3947 if (item) {
3948 if (!was_schedule_incremented)
3949 log_debug(LD_DIR, "%s %s %d time(s); I'll try again %s.",
3950 item, increment_action, (int)dls_n_download_increments,
3951 not_incremented_response);
3952 else if (increment == 0)
3953 log_debug(LD_DIR, "%s %s %d time(s); I'll try again immediately.",
3954 item, increment_action, (int)dls_n_download_increments);
3955 else if (dls_next_attempt_at < TIME_MAX)
3956 log_debug(LD_DIR, "%s %s %d time(s); I'll try again in %d seconds.",
3957 item, increment_action, (int)dls_n_download_increments,
3958 (int)(dls_next_attempt_at-now));
3959 else
3960 log_debug(LD_DIR, "%s %s %d time(s); Giving up for a while.",
3961 item, increment_action, (int)dls_n_download_increments);
3965 /** Determine when a failed download attempt should be retried.
3966 * Called when an attempt to download <b>dls</b> has failed with HTTP status
3967 * <b>status_code</b>. Increment the failure count (if the code indicates a
3968 * real failure, or if we're a server) and set <b>dls</b>-\>next_attempt_at to
3969 * an appropriate time in the future and return it.
3970 * If <b>dls->increment_on</b> is DL_SCHED_INCREMENT_ATTEMPT, increment the
3971 * failure count, and return a time in the far future for the next attempt (to
3972 * avoid an immediate retry). */
3973 time_t
3974 download_status_increment_failure(download_status_t *dls, int status_code,
3975 const char *item, int server, time_t now)
3977 int increment = -1;
3978 tor_assert(dls);
3980 /* only count the failure if it's permanent, or we're a server */
3981 if (status_code != 503 || server) {
3982 if (dls->n_download_failures < IMPOSSIBLE_TO_DOWNLOAD-1)
3983 ++dls->n_download_failures;
3986 if (dls->increment_on == DL_SCHED_INCREMENT_FAILURE) {
3987 /* We don't find out that a failure-based schedule has attempted a
3988 * connection until that connection fails.
3989 * We'll never find out about successful connections, but this doesn't
3990 * matter, because schedules are reset after a successful download.
3992 if (dls->n_download_attempts < IMPOSSIBLE_TO_DOWNLOAD-1)
3993 ++dls->n_download_attempts;
3995 /* only return a failure retry time if this schedule increments on failures
3997 const smartlist_t *schedule = find_dl_schedule(dls, get_options());
3998 increment = download_status_schedule_get_delay(dls, schedule, now);
4001 download_status_log_helper(item, !dls->increment_on, "failed",
4002 "concurrently", dls->n_download_failures,
4003 increment, dls->next_attempt_at, now);
4005 if (dls->increment_on == DL_SCHED_INCREMENT_ATTEMPT) {
4006 /* stop this schedule retrying on failure, it will launch concurrent
4007 * connections instead */
4008 return TIME_MAX;
4009 } else {
4010 return dls->next_attempt_at;
4014 /** Determine when the next download attempt should be made when using an
4015 * attempt-based (potentially concurrent) download schedule.
4016 * Called when an attempt to download <b>dls</b> is being initiated.
4017 * Increment the attempt count and set <b>dls</b>-\>next_attempt_at to an
4018 * appropriate time in the future and return it.
4019 * If <b>dls->increment_on</b> is DL_SCHED_INCREMENT_FAILURE, don't increment
4020 * the attempts, and return a time in the far future (to avoid launching a
4021 * concurrent attempt). */
4022 time_t
4023 download_status_increment_attempt(download_status_t *dls, const char *item,
4024 time_t now)
4026 int delay = -1;
4027 tor_assert(dls);
4029 if (dls->increment_on == DL_SCHED_INCREMENT_FAILURE) {
4030 /* this schedule should retry on failure, and not launch any concurrent
4031 attempts */
4032 log_info(LD_BUG, "Tried to launch an attempt-based connection on a "
4033 "failure-based schedule.");
4034 return TIME_MAX;
4037 if (dls->n_download_attempts < IMPOSSIBLE_TO_DOWNLOAD-1)
4038 ++dls->n_download_attempts;
4040 const smartlist_t *schedule = find_dl_schedule(dls, get_options());
4041 delay = download_status_schedule_get_delay(dls, schedule, now);
4043 download_status_log_helper(item, dls->increment_on, "attempted",
4044 "on failure", dls->n_download_attempts,
4045 delay, dls->next_attempt_at, now);
4047 return dls->next_attempt_at;
4050 /** Reset <b>dls</b> so that it will be considered downloadable
4051 * immediately, and/or to show that we don't need it anymore.
4053 * Must be called to initialise a download schedule, otherwise the zeroth item
4054 * in the schedule will never be used.
4056 * (We find the zeroth element of the download schedule, and set
4057 * next_attempt_at to be the appropriate offset from 'now'. In most
4058 * cases this means setting it to 'now', so the item will be immediately
4059 * downloadable; in the case of bridge descriptors, the zeroth element
4060 * is an hour from now.) */
4061 void
4062 download_status_reset(download_status_t *dls)
4064 if (dls->n_download_failures == IMPOSSIBLE_TO_DOWNLOAD
4065 || dls->n_download_attempts == IMPOSSIBLE_TO_DOWNLOAD)
4066 return; /* Don't reset this. */
4068 const smartlist_t *schedule = find_dl_schedule(dls, get_options());
4070 dls->n_download_failures = 0;
4071 dls->n_download_attempts = 0;
4072 dls->next_attempt_at = time(NULL) + *(int *)smartlist_get(schedule, 0);
4073 /* Don't reset dls->want_authority or dls->increment_on */
4076 /** Return the number of failures on <b>dls</b> since the last success (if
4077 * any). */
4079 download_status_get_n_failures(const download_status_t *dls)
4081 return dls->n_download_failures;
4084 /** Return the number of attempts to download <b>dls</b> since the last success
4085 * (if any). This can differ from download_status_get_n_failures() due to
4086 * outstanding concurrent attempts. */
4088 download_status_get_n_attempts(const download_status_t *dls)
4090 return dls->n_download_attempts;
4093 /** Return the next time to attempt to download <b>dls</b>. */
4094 time_t
4095 download_status_get_next_attempt_at(const download_status_t *dls)
4097 return dls->next_attempt_at;
4100 /** Called when one or more routerdesc (or extrainfo, if <b>was_extrainfo</b>)
4101 * fetches have failed (with uppercase fingerprints listed in <b>failed</b>,
4102 * either as descriptor digests or as identity digests based on
4103 * <b>was_descriptor_digests</b>).
4105 static void
4106 dir_routerdesc_download_failed(smartlist_t *failed, int status_code,
4107 int router_purpose,
4108 int was_extrainfo, int was_descriptor_digests)
4110 char digest[DIGEST_LEN];
4111 time_t now = time(NULL);
4112 int server = directory_fetches_from_authorities(get_options());
4113 if (!was_descriptor_digests) {
4114 if (router_purpose == ROUTER_PURPOSE_BRIDGE) {
4115 tor_assert(!was_extrainfo);
4116 connection_dir_retry_bridges(failed);
4118 return; /* FFFF should implement for other-than-router-purpose someday */
4120 SMARTLIST_FOREACH_BEGIN(failed, const char *, cp) {
4121 download_status_t *dls = NULL;
4122 if (base16_decode(digest, DIGEST_LEN, cp, strlen(cp)) < 0) {
4123 log_warn(LD_BUG, "Malformed fingerprint in list: %s", escaped(cp));
4124 continue;
4126 if (was_extrainfo) {
4127 signed_descriptor_t *sd =
4128 router_get_by_extrainfo_digest(digest);
4129 if (sd)
4130 dls = &sd->ei_dl_status;
4131 } else {
4132 dls = router_get_dl_status_by_descriptor_digest(digest);
4134 if (!dls || dls->n_download_failures >=
4135 get_options()->TestingDescriptorMaxDownloadTries)
4136 continue;
4137 download_status_increment_failure(dls, status_code, cp, server, now);
4138 } SMARTLIST_FOREACH_END(cp);
4140 /* No need to relaunch descriptor downloads here: we already do it
4141 * every 10 or 60 seconds (FOO_DESCRIPTOR_RETRY_INTERVAL) in main.c. */
4144 /** Called when a connection to download microdescriptors has failed in whole
4145 * or in part. <b>failed</b> is a list of every microdesc digest we didn't
4146 * get. <b>status_code</b> is the http status code we received. Reschedule the
4147 * microdesc downloads as appropriate. */
4148 static void
4149 dir_microdesc_download_failed(smartlist_t *failed,
4150 int status_code)
4152 networkstatus_t *consensus
4153 = networkstatus_get_latest_consensus_by_flavor(FLAV_MICRODESC);
4154 routerstatus_t *rs;
4155 download_status_t *dls;
4156 time_t now = time(NULL);
4157 int server = directory_fetches_from_authorities(get_options());
4159 if (! consensus)
4160 return;
4161 SMARTLIST_FOREACH_BEGIN(failed, const char *, d) {
4162 rs = router_get_mutable_consensus_status_by_descriptor_digest(consensus,d);
4163 if (!rs)
4164 continue;
4165 dls = &rs->dl_status;
4166 if (dls->n_download_failures >=
4167 get_options()->TestingMicrodescMaxDownloadTries)
4168 continue;
4170 char buf[BASE64_DIGEST256_LEN+1];
4171 digest256_to_base64(buf, d);
4172 download_status_increment_failure(dls, status_code, buf,
4173 server, now);
4175 } SMARTLIST_FOREACH_END(d);
4178 /** Helper. Compare two fp_pair_t objects, and return negative, 0, or
4179 * positive as appropriate. */
4180 static int
4181 compare_pairs_(const void **a, const void **b)
4183 const fp_pair_t *fp1 = *a, *fp2 = *b;
4184 int r;
4185 if ((r = fast_memcmp(fp1->first, fp2->first, DIGEST_LEN)))
4186 return r;
4187 else
4188 return fast_memcmp(fp1->second, fp2->second, DIGEST_LEN);
4191 /** Divide a string <b>res</b> of the form FP1-FP2+FP3-FP4...[.z], where each
4192 * FP is a hex-encoded fingerprint, into a sequence of distinct sorted
4193 * fp_pair_t. Skip malformed pairs. On success, return 0 and add those
4194 * fp_pair_t into <b>pairs_out</b>. On failure, return -1. */
4196 dir_split_resource_into_fingerprint_pairs(const char *res,
4197 smartlist_t *pairs_out)
4199 smartlist_t *pairs_tmp = smartlist_new();
4200 smartlist_t *pairs_result = smartlist_new();
4202 smartlist_split_string(pairs_tmp, res, "+", 0, 0);
4203 if (smartlist_len(pairs_tmp)) {
4204 char *last = smartlist_get(pairs_tmp,smartlist_len(pairs_tmp)-1);
4205 size_t last_len = strlen(last);
4206 if (last_len > 2 && !strcmp(last+last_len-2, ".z")) {
4207 last[last_len-2] = '\0';
4210 SMARTLIST_FOREACH_BEGIN(pairs_tmp, char *, cp) {
4211 if (strlen(cp) != HEX_DIGEST_LEN*2+1) {
4212 log_info(LD_DIR,
4213 "Skipping digest pair %s with non-standard length.", escaped(cp));
4214 } else if (cp[HEX_DIGEST_LEN] != '-') {
4215 log_info(LD_DIR,
4216 "Skipping digest pair %s with missing dash.", escaped(cp));
4217 } else {
4218 fp_pair_t pair;
4219 if (base16_decode(pair.first, DIGEST_LEN, cp, HEX_DIGEST_LEN)<0 ||
4220 base16_decode(pair.second,
4221 DIGEST_LEN, cp+HEX_DIGEST_LEN+1, HEX_DIGEST_LEN)<0) {
4222 log_info(LD_DIR, "Skipping non-decodable digest pair %s", escaped(cp));
4223 } else {
4224 smartlist_add(pairs_result, tor_memdup(&pair, sizeof(pair)));
4227 tor_free(cp);
4228 } SMARTLIST_FOREACH_END(cp);
4229 smartlist_free(pairs_tmp);
4231 /* Uniq-and-sort */
4232 smartlist_sort(pairs_result, compare_pairs_);
4233 smartlist_uniq(pairs_result, compare_pairs_, tor_free_);
4235 smartlist_add_all(pairs_out, pairs_result);
4236 smartlist_free(pairs_result);
4237 return 0;
4240 /** Given a directory <b>resource</b> request, containing zero
4241 * or more strings separated by plus signs, followed optionally by ".z", store
4242 * the strings, in order, into <b>fp_out</b>. If <b>compressed_out</b> is
4243 * non-NULL, set it to 1 if the resource ends in ".z", else set it to 0.
4245 * If (flags & DSR_HEX), then delete all elements that aren't hex digests, and
4246 * decode the rest. If (flags & DSR_BASE64), then use "-" rather than "+" as
4247 * a separator, delete all the elements that aren't base64-encoded digests,
4248 * and decode the rest. If (flags & DSR_DIGEST256), these digests should be
4249 * 256 bits long; else they should be 160.
4251 * If (flags & DSR_SORT_UNIQ), then sort the list and remove all duplicates.
4254 dir_split_resource_into_fingerprints(const char *resource,
4255 smartlist_t *fp_out, int *compressed_out,
4256 int flags)
4258 const int decode_hex = flags & DSR_HEX;
4259 const int decode_base64 = flags & DSR_BASE64;
4260 const int digests_are_256 = flags & DSR_DIGEST256;
4261 const int sort_uniq = flags & DSR_SORT_UNIQ;
4263 const int digest_len = digests_are_256 ? DIGEST256_LEN : DIGEST_LEN;
4264 const int hex_digest_len = digests_are_256 ?
4265 HEX_DIGEST256_LEN : HEX_DIGEST_LEN;
4266 const int base64_digest_len = digests_are_256 ?
4267 BASE64_DIGEST256_LEN : BASE64_DIGEST_LEN;
4268 smartlist_t *fp_tmp = smartlist_new();
4270 tor_assert(!(decode_hex && decode_base64));
4271 tor_assert(fp_out);
4273 smartlist_split_string(fp_tmp, resource, decode_base64?"-":"+", 0, 0);
4274 if (compressed_out)
4275 *compressed_out = 0;
4276 if (smartlist_len(fp_tmp)) {
4277 char *last = smartlist_get(fp_tmp,smartlist_len(fp_tmp)-1);
4278 size_t last_len = strlen(last);
4279 if (last_len > 2 && !strcmp(last+last_len-2, ".z")) {
4280 last[last_len-2] = '\0';
4281 if (compressed_out)
4282 *compressed_out = 1;
4285 if (decode_hex || decode_base64) {
4286 const size_t encoded_len = decode_hex ? hex_digest_len : base64_digest_len;
4287 int i;
4288 char *cp, *d = NULL;
4289 for (i = 0; i < smartlist_len(fp_tmp); ++i) {
4290 cp = smartlist_get(fp_tmp, i);
4291 if (strlen(cp) != encoded_len) {
4292 log_info(LD_DIR,
4293 "Skipping digest %s with non-standard length.", escaped(cp));
4294 smartlist_del_keeporder(fp_tmp, i--);
4295 goto again;
4297 d = tor_malloc_zero(digest_len);
4298 if (decode_hex ?
4299 (base16_decode(d, digest_len, cp, hex_digest_len)<0) :
4300 (base64_decode(d, digest_len, cp, base64_digest_len)<0)) {
4301 log_info(LD_DIR, "Skipping non-decodable digest %s", escaped(cp));
4302 smartlist_del_keeporder(fp_tmp, i--);
4303 goto again;
4305 smartlist_set(fp_tmp, i, d);
4306 d = NULL;
4307 again:
4308 tor_free(cp);
4309 tor_free(d);
4312 if (sort_uniq) {
4313 if (decode_hex || decode_base64) {
4314 if (digests_are_256) {
4315 smartlist_sort_digests256(fp_tmp);
4316 smartlist_uniq_digests256(fp_tmp);
4317 } else {
4318 smartlist_sort_digests(fp_tmp);
4319 smartlist_uniq_digests(fp_tmp);
4321 } else {
4322 smartlist_sort_strings(fp_tmp);
4323 smartlist_uniq_strings(fp_tmp);
4326 smartlist_add_all(fp_out, fp_tmp);
4327 smartlist_free(fp_tmp);
4328 return 0;