Send control port events for timeouts.
[tor.git] / src / or / directory.c
blobb109cb53a79af016bdc7be7d0eaada33264f40f4
1 /* Copyright (c) 2001-2004, Roger Dingledine.
2 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
3 * Copyright (c) 2007-2010, The Tor Project, Inc. */
4 /* See LICENSE for licensing information */
6 #include "or.h"
7 #include "buffers.h"
8 #include "circuitbuild.h"
9 #include "config.h"
10 #include "connection.h"
11 #include "connection_edge.h"
12 #include "control.h"
13 #include "directory.h"
14 #include "dirserv.h"
15 #include "dirvote.h"
16 #include "geoip.h"
17 #include "main.h"
18 #include "networkstatus.h"
19 #include "policies.h"
20 #include "rendclient.h"
21 #include "rendcommon.h"
22 #include "rephist.h"
23 #include "router.h"
24 #include "routerlist.h"
25 #include "routerparse.h"
27 #if defined(EXPORTMALLINFO) && defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO)
28 #ifndef OPENBSD
29 #include <malloc.h>
30 #endif
31 #endif
33 /**
34 * \file directory.c
35 * \brief Code to send and fetch directories and router
36 * descriptors via HTTP. Directories use dirserv.c to generate the
37 * results; clients use routers.c to parse them.
38 **/
40 /* In-points to directory.c:
42 * - directory_post_to_dirservers(), called from
43 * router_upload_dir_desc_to_dirservers() in router.c
44 * upload_service_descriptor() in rendservice.c
45 * - directory_get_from_dirserver(), called from
46 * rend_client_refetch_renddesc() in rendclient.c
47 * run_scheduled_events() in main.c
48 * do_hup() in main.c
49 * - connection_dir_process_inbuf(), called from
50 * connection_process_inbuf() in connection.c
51 * - connection_dir_finished_flushing(), called from
52 * connection_finished_flushing() in connection.c
53 * - connection_dir_finished_connecting(), called from
54 * connection_finished_connecting() in connection.c
56 static void directory_send_command(dir_connection_t *conn,
57 int purpose, int direct, const char *resource,
58 const char *payload, size_t payload_len,
59 int supports_conditional_consensus,
60 time_t if_modified_since);
61 static int directory_handle_command(dir_connection_t *conn);
62 static int body_is_plausible(const char *body, size_t body_len, int purpose);
63 static int purpose_needs_anonymity(uint8_t dir_purpose,
64 uint8_t router_purpose);
65 static char *http_get_header(const char *headers, const char *which);
66 static void http_set_address_origin(const char *headers, connection_t *conn);
67 static void connection_dir_download_networkstatus_failed(
68 dir_connection_t *conn, int status_code);
69 static void connection_dir_download_routerdesc_failed(dir_connection_t *conn);
70 static void connection_dir_bridge_routerdesc_failed(dir_connection_t *conn);
71 static void connection_dir_download_cert_failed(
72 dir_connection_t *conn, int status_code);
73 static void connection_dir_retry_bridges(smartlist_t *descs);
74 static void dir_networkstatus_download_failed(smartlist_t *failed,
75 int status_code);
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 note_client_request(int purpose, int compressed, size_t bytes);
82 static int client_likes_consensus(networkstatus_t *v, const char *want_url);
84 static void directory_initiate_command_rend(const char *address,
85 const tor_addr_t *addr,
86 uint16_t or_port,
87 uint16_t dir_port,
88 int supports_conditional_consensus,
89 int supports_begindir,
90 const char *digest,
91 uint8_t dir_purpose,
92 uint8_t router_purpose,
93 int anonymized_connection,
94 const char *resource,
95 const char *payload,
96 size_t payload_len,
97 time_t if_modified_since,
98 const rend_data_t *rend_query);
100 /********* START VARIABLES **********/
102 /** How far in the future do we allow a directory server to tell us it is
103 * before deciding that one of us has the wrong time? */
104 #define ALLOW_DIRECTORY_TIME_SKEW (30*60)
106 #define X_ADDRESS_HEADER "X-Your-Address-Is: "
108 /** HTTP cache control: how long do we tell proxies they can cache each
109 * kind of document we serve? */
110 #define FULL_DIR_CACHE_LIFETIME (60*60)
111 #define RUNNINGROUTERS_CACHE_LIFETIME (20*60)
112 #define DIRPORTFRONTPAGE_CACHE_LIFETIME (20*60)
113 #define NETWORKSTATUS_CACHE_LIFETIME (5*60)
114 #define ROUTERDESC_CACHE_LIFETIME (30*60)
115 #define ROUTERDESC_BY_DIGEST_CACHE_LIFETIME (48*60*60)
116 #define ROBOTS_CACHE_LIFETIME (24*60*60)
117 #define MICRODESC_CACHE_LIFETIME (48*60*60)
119 /********* END VARIABLES ************/
121 /** Return true iff the directory purpose <b>dir_purpose</b> (and if it's
122 * fetching descriptors, it's fetching them for <b>router_purpose</b>)
123 * must use an anonymous connection to a directory. */
124 static int
125 purpose_needs_anonymity(uint8_t dir_purpose, uint8_t router_purpose)
127 if (get_options()->AllDirActionsPrivate)
128 return 1;
129 if (router_purpose == ROUTER_PURPOSE_BRIDGE && can_complete_circuit)
130 return 1; /* if no circuits yet, we may need this info to bootstrap. */
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_V2_NETWORKSTATUS ||
135 dir_purpose == DIR_PURPOSE_FETCH_STATUS_VOTE ||
136 dir_purpose == DIR_PURPOSE_FETCH_DETACHED_SIGNATURES ||
137 dir_purpose == DIR_PURPOSE_FETCH_CONSENSUS ||
138 dir_purpose == DIR_PURPOSE_FETCH_CERTIFICATE ||
139 dir_purpose == DIR_PURPOSE_FETCH_SERVERDESC ||
140 dir_purpose == DIR_PURPOSE_FETCH_EXTRAINFO)
141 return 0;
142 return 1;
145 /** Return a newly allocated string describing <b>auth</b>. */
146 char *
147 authority_type_to_string(authority_type_t auth)
149 char *result;
150 smartlist_t *lst = smartlist_create();
151 if (auth & V1_AUTHORITY)
152 smartlist_add(lst, (void*)"V1");
153 if (auth & V2_AUTHORITY)
154 smartlist_add(lst, (void*)"V2");
155 if (auth & V3_AUTHORITY)
156 smartlist_add(lst, (void*)"V3");
157 if (auth & BRIDGE_AUTHORITY)
158 smartlist_add(lst, (void*)"Bridge");
159 if (auth & HIDSERV_AUTHORITY)
160 smartlist_add(lst, (void*)"Hidden service");
161 if (smartlist_len(lst)) {
162 result = smartlist_join_strings(lst, ", ", 0, NULL);
163 } else {
164 result = tor_strdup("[Not an authority]");
166 smartlist_free(lst);
167 return result;
170 /** Return a string describing a given directory connection purpose. */
171 static const char *
172 dir_conn_purpose_to_string(int purpose)
174 switch (purpose)
176 case DIR_PURPOSE_FETCH_RENDDESC:
177 return "hidden-service descriptor fetch";
178 case DIR_PURPOSE_UPLOAD_DIR:
179 return "server descriptor upload";
180 case DIR_PURPOSE_UPLOAD_RENDDESC:
181 return "hidden-service descriptor upload";
182 case DIR_PURPOSE_UPLOAD_VOTE:
183 return "server vote upload";
184 case DIR_PURPOSE_UPLOAD_SIGNATURES:
185 return "consensus signature upload";
186 case DIR_PURPOSE_FETCH_V2_NETWORKSTATUS:
187 return "network-status fetch";
188 case DIR_PURPOSE_FETCH_SERVERDESC:
189 return "server descriptor fetch";
190 case DIR_PURPOSE_FETCH_EXTRAINFO:
191 return "extra-info fetch";
192 case DIR_PURPOSE_FETCH_CONSENSUS:
193 return "consensus network-status fetch";
194 case DIR_PURPOSE_FETCH_CERTIFICATE:
195 return "authority cert fetch";
196 case DIR_PURPOSE_FETCH_STATUS_VOTE:
197 return "status vote fetch";
198 case DIR_PURPOSE_FETCH_DETACHED_SIGNATURES:
199 return "consensus signature fetch";
200 case DIR_PURPOSE_FETCH_RENDDESC_V2:
201 return "hidden-service v2 descriptor fetch";
202 case DIR_PURPOSE_UPLOAD_RENDDESC_V2:
203 return "hidden-service v2 descriptor upload";
206 log_warn(LD_BUG, "Called with unknown purpose %d", purpose);
207 return "(unknown)";
210 /** Return true iff <b>identity_digest</b> is the digest of a router we
211 * believe to support extrainfo downloads. (If <b>is_authority</b> we do
212 * additional checking that's only valid for authorities.) */
214 router_supports_extrainfo(const char *identity_digest, int is_authority)
216 routerinfo_t *ri = router_get_by_digest(identity_digest);
218 if (ri) {
219 if (ri->caches_extra_info)
220 return 1;
221 if (is_authority && ri->platform &&
222 tor_version_as_new_as(ri->platform, "Tor 0.2.0.0-alpha-dev (r10070)"))
223 return 1;
225 if (is_authority) {
226 routerstatus_t *rs = router_get_consensus_status_by_id(identity_digest);
227 if (rs && rs->version_supports_extrainfo_upload)
228 return 1;
230 return 0;
233 /** Return true iff any trusted directory authority has accepted our
234 * server descriptor.
236 * We consider any authority sufficient because waiting for all of
237 * them means it never happens while any authority is down; we don't
238 * go for something more complex in the middle (like \>1/3 or \>1/2 or
239 * \>=1/2) because that doesn't seem necessary yet.
242 directories_have_accepted_server_descriptor(void)
244 smartlist_t *servers = router_get_trusted_dir_servers();
245 or_options_t *options = get_options();
246 SMARTLIST_FOREACH(servers, trusted_dir_server_t *, d, {
247 if ((d->type & options->_PublishServerDescriptor) &&
248 d->has_accepted_serverdesc) {
249 return 1;
252 return 0;
255 /** Start a connection to every suitable directory authority, using
256 * connection purpose 'purpose' and uploading the payload 'payload'
257 * (length 'payload_len'). dir_purpose should be one of
258 * 'DIR_PURPOSE_UPLOAD_DIR' or 'DIR_PURPOSE_UPLOAD_RENDDESC'.
260 * <b>type</b> specifies what sort of dir authorities (V1, V2,
261 * HIDSERV, BRIDGE) we should upload to.
263 * If <b>extrainfo_len</b> is nonzero, the first <b>payload_len</b> bytes of
264 * <b>payload</b> hold a router descriptor, and the next <b>extrainfo_len</b>
265 * bytes of <b>payload</b> hold an extra-info document. Upload the descriptor
266 * to all authorities, and the extra-info document to all authorities that
267 * support it.
269 void
270 directory_post_to_dirservers(uint8_t dir_purpose, uint8_t router_purpose,
271 authority_type_t type,
272 const char *payload,
273 size_t payload_len, size_t extrainfo_len)
275 int post_via_tor;
276 smartlist_t *dirservers = router_get_trusted_dir_servers();
277 int found = 0;
278 tor_assert(dirservers);
279 /* This tries dirservers which we believe to be down, but ultimately, that's
280 * harmless, and we may as well err on the side of getting things uploaded.
282 SMARTLIST_FOREACH_BEGIN(dirservers, trusted_dir_server_t *, ds) {
283 routerstatus_t *rs = &(ds->fake_status);
284 size_t upload_len = payload_len;
285 tor_addr_t ds_addr;
287 if ((type & ds->type) == 0)
288 continue;
290 found = 1; /* at least one authority of this type was listed */
291 if (dir_purpose == DIR_PURPOSE_UPLOAD_DIR)
292 ds->has_accepted_serverdesc = 0;
294 if (extrainfo_len && router_supports_extrainfo(ds->digest, 1)) {
295 upload_len += extrainfo_len;
296 log_info(LD_DIR, "Uploading an extrainfo too (length %d)",
297 (int) extrainfo_len);
299 tor_addr_from_ipv4h(&ds_addr, ds->addr);
300 post_via_tor = purpose_needs_anonymity(dir_purpose, router_purpose) ||
301 !fascist_firewall_allows_address_dir(&ds_addr, ds->dir_port);
302 directory_initiate_command_routerstatus(rs, dir_purpose,
303 router_purpose,
304 post_via_tor,
305 NULL, payload, upload_len, 0);
306 } SMARTLIST_FOREACH_END(ds);
307 if (!found) {
308 char *s = authority_type_to_string(type);
309 log_warn(LD_DIR, "Publishing server descriptor to directory authorities "
310 "of type '%s', but no authorities of that type listed!", s);
311 tor_free(s);
315 /** Start a connection to a random running directory server, using
316 * connection purpose <b>dir_purpose</b>, intending to fetch descriptors
317 * of purpose <b>router_purpose</b>, and requesting <b>resource</b>.
318 * Use <b>pds_flags</b> as arguments to router_pick_directory_server()
319 * or router_pick_trusteddirserver().
321 void
322 directory_get_from_dirserver(uint8_t dir_purpose, uint8_t router_purpose,
323 const char *resource, int pds_flags)
325 routerstatus_t *rs = NULL;
326 or_options_t *options = get_options();
327 int prefer_authority = directory_fetches_from_authorities(options);
328 int get_via_tor = purpose_needs_anonymity(dir_purpose, router_purpose);
329 authority_type_t type;
330 time_t if_modified_since = 0;
332 /* FFFF we could break this switch into its own function, and call
333 * it elsewhere in directory.c. -RD */
334 switch (dir_purpose) {
335 case DIR_PURPOSE_FETCH_EXTRAINFO:
336 type = EXTRAINFO_CACHE |
337 (router_purpose == ROUTER_PURPOSE_BRIDGE ? BRIDGE_AUTHORITY :
338 V3_AUTHORITY);
339 break;
340 case DIR_PURPOSE_FETCH_V2_NETWORKSTATUS:
341 type = V2_AUTHORITY;
342 break;
343 case DIR_PURPOSE_FETCH_SERVERDESC:
344 type = (router_purpose == ROUTER_PURPOSE_BRIDGE ? BRIDGE_AUTHORITY :
345 V3_AUTHORITY);
346 break;
347 case DIR_PURPOSE_FETCH_RENDDESC:
348 type = HIDSERV_AUTHORITY;
349 break;
350 case DIR_PURPOSE_FETCH_STATUS_VOTE:
351 case DIR_PURPOSE_FETCH_DETACHED_SIGNATURES:
352 type = V3_AUTHORITY;
353 break;
354 case DIR_PURPOSE_FETCH_CONSENSUS:
355 case DIR_PURPOSE_FETCH_CERTIFICATE:
356 type = V3_AUTHORITY;
357 break;
358 default:
359 log_warn(LD_BUG, "Unexpected purpose %d", (int)dir_purpose);
360 return;
363 if (dir_purpose == DIR_PURPOSE_FETCH_CONSENSUS) {
364 networkstatus_t *v = networkstatus_get_latest_consensus();
365 if (v)
366 if_modified_since = v->valid_after + 180;
369 if (!options->FetchServerDescriptors && type != HIDSERV_AUTHORITY)
370 return;
372 if (!get_via_tor) {
373 if (options->UseBridges && type != BRIDGE_AUTHORITY) {
374 /* want to ask a running bridge for which we have a descriptor. */
375 /* XXX022 we assume that all of our bridges can answer any
376 * possible directory question. This won't be true forever. -RD */
377 /* It certainly is not true with conditional consensus downloading,
378 * so, for now, never assume the server supports that. */
379 routerinfo_t *ri = choose_random_entry(NULL);
380 if (ri) {
381 tor_addr_t addr;
382 tor_addr_from_ipv4h(&addr, ri->addr);
383 directory_initiate_command(ri->address, &addr,
384 ri->or_port, 0,
385 0, /* don't use conditional consensus url */
386 1, ri->cache_info.identity_digest,
387 dir_purpose,
388 router_purpose,
389 0, resource, NULL, 0, if_modified_since);
390 } else
391 log_notice(LD_DIR, "Ignoring directory request, since no bridge "
392 "nodes are available yet.");
393 return;
394 } else {
395 if (prefer_authority || type == BRIDGE_AUTHORITY) {
396 /* only ask authdirservers, and don't ask myself */
397 rs = router_pick_trusteddirserver(type, pds_flags);
398 if (rs == NULL && (pds_flags & PDS_NO_EXISTING_SERVERDESC_FETCH)) {
399 /* We don't want to fetch from any authorities that we're currently
400 * fetching server descriptors from, and we got no match. Did we
401 * get no match because all the authorities have connections
402 * fetching server descriptors (in which case we should just
403 * return,) or because all the authorities are down or on fire or
404 * unreachable or something (in which case we should go on with
405 * our fallback code)? */
406 pds_flags &= ~PDS_NO_EXISTING_SERVERDESC_FETCH;
407 rs = router_pick_trusteddirserver(type, pds_flags);
408 if (rs) {
409 log_debug(LD_DIR, "Deferring serverdesc fetch: all authorities "
410 "are in use.");
411 return;
415 if (!rs && type != BRIDGE_AUTHORITY) {
416 /* anybody with a non-zero dirport will do */
417 rs = router_pick_directory_server(type, pds_flags);
418 if (!rs) {
419 log_info(LD_DIR, "No router found for %s; falling back to "
420 "dirserver list.", dir_conn_purpose_to_string(dir_purpose));
421 rs = router_pick_trusteddirserver(type, pds_flags);
422 if (!rs)
423 get_via_tor = 1; /* last resort: try routing it via Tor */
427 } else { /* get_via_tor */
428 /* Never use fascistfirewall; we're going via Tor. */
429 if (dir_purpose == DIR_PURPOSE_FETCH_RENDDESC) {
430 /* only ask hidserv authorities, any of them will do */
431 pds_flags |= PDS_IGNORE_FASCISTFIREWALL|PDS_ALLOW_SELF;
432 rs = router_pick_trusteddirserver(HIDSERV_AUTHORITY, pds_flags);
433 } else {
434 /* anybody with a non-zero dirport will do. Disregard firewalls. */
435 pds_flags |= PDS_IGNORE_FASCISTFIREWALL;
436 rs = router_pick_directory_server(type, pds_flags);
437 /* If we have any hope of building an indirect conn, we know some router
438 * descriptors. If (rs==NULL), we can't build circuits anyway, so
439 * there's no point in falling back to the authorities in this case. */
443 if (rs)
444 directory_initiate_command_routerstatus(rs, dir_purpose,
445 router_purpose,
446 get_via_tor,
447 resource, NULL, 0,
448 if_modified_since);
449 else {
450 log_notice(LD_DIR,
451 "While fetching directory info, "
452 "no running dirservers known. Will try again later. "
453 "(purpose %d)", dir_purpose);
454 if (!purpose_needs_anonymity(dir_purpose, router_purpose)) {
455 /* remember we tried them all and failed. */
456 directory_all_unreachable(time(NULL));
461 /** As directory_get_from_dirserver, but initiates a request to <i>every</i>
462 * directory authority other than ourself. Only for use by authorities when
463 * searching for missing information while voting. */
464 void
465 directory_get_from_all_authorities(uint8_t dir_purpose,
466 uint8_t router_purpose,
467 const char *resource)
469 tor_assert(dir_purpose == DIR_PURPOSE_FETCH_STATUS_VOTE ||
470 dir_purpose == DIR_PURPOSE_FETCH_DETACHED_SIGNATURES);
472 SMARTLIST_FOREACH(router_get_trusted_dir_servers(),
473 trusted_dir_server_t *, ds,
475 routerstatus_t *rs;
476 if (router_digest_is_me(ds->digest))
477 continue;
478 if (!(ds->type & V3_AUTHORITY))
479 continue;
480 rs = &ds->fake_status;
481 directory_initiate_command_routerstatus(rs, dir_purpose, router_purpose,
482 0, resource, NULL, 0, 0);
486 /** Same as directory_initiate_command_routerstatus(), but accepts
487 * rendezvous data to fetch a hidden service descriptor. */
488 void
489 directory_initiate_command_routerstatus_rend(routerstatus_t *status,
490 uint8_t dir_purpose,
491 uint8_t router_purpose,
492 int anonymized_connection,
493 const char *resource,
494 const char *payload,
495 size_t payload_len,
496 time_t if_modified_since,
497 const rend_data_t *rend_query)
499 routerinfo_t *router;
500 char address_buf[INET_NTOA_BUF_LEN+1];
501 struct in_addr in;
502 const char *address;
503 tor_addr_t addr;
504 router = router_get_by_digest(status->identity_digest);
505 if (!router && anonymized_connection) {
506 log_info(LD_DIR, "Not sending anonymized request to directory '%s'; we "
507 "don't have its router descriptor.", status->nickname);
508 return;
509 } else if (router) {
510 address = router->address;
511 } else {
512 in.s_addr = htonl(status->addr);
513 tor_inet_ntoa(&in, address_buf, sizeof(address_buf));
514 address = address_buf;
516 tor_addr_from_ipv4h(&addr, status->addr);
517 directory_initiate_command_rend(address, &addr,
518 status->or_port, status->dir_port,
519 status->version_supports_conditional_consensus,
520 status->version_supports_begindir,
521 status->identity_digest,
522 dir_purpose, router_purpose,
523 anonymized_connection, resource,
524 payload, payload_len, if_modified_since,
525 rend_query);
528 /** Launch a new connection to the directory server <b>status</b> to
529 * upload or download a server or rendezvous
530 * descriptor. <b>dir_purpose</b> determines what
531 * kind of directory connection we're launching, and must be one of
532 * DIR_PURPOSE_{FETCH|UPLOAD}_{DIR|RENDDESC|RENDDESC_V2}. <b>router_purpose</b>
533 * specifies the descriptor purposes we have in mind (currently only
534 * used for FETCH_DIR).
536 * When uploading, <b>payload</b> and <b>payload_len</b> determine the content
537 * of the HTTP post. Otherwise, <b>payload</b> should be NULL.
539 * When fetching a rendezvous descriptor, <b>resource</b> is the service ID we
540 * want to fetch.
542 void
543 directory_initiate_command_routerstatus(routerstatus_t *status,
544 uint8_t dir_purpose,
545 uint8_t router_purpose,
546 int anonymized_connection,
547 const char *resource,
548 const char *payload,
549 size_t payload_len,
550 time_t if_modified_since)
552 directory_initiate_command_routerstatus_rend(status, dir_purpose,
553 router_purpose,
554 anonymized_connection, resource,
555 payload, payload_len,
556 if_modified_since, NULL);
559 /** Return true iff <b>conn</b> is the client side of a directory connection
560 * we launched to ourself in order to determine the reachability of our
561 * dir_port. */
562 static int
563 directory_conn_is_self_reachability_test(dir_connection_t *conn)
565 if (conn->requested_resource &&
566 !strcmpstart(conn->requested_resource,"authority")) {
567 routerinfo_t *me = router_get_my_routerinfo();
568 if (me &&
569 router_digest_is_me(conn->identity_digest) &&
570 tor_addr_eq_ipv4h(&conn->_base.addr, me->addr) && /*XXXX prop 118*/
571 me->dir_port == conn->_base.port)
572 return 1;
574 return 0;
577 /** Called when we are unable to complete the client's request to a directory
578 * server due to a network error: Mark the router as down and try again if
579 * possible.
581 void
582 connection_dir_request_failed(dir_connection_t *conn)
584 if (directory_conn_is_self_reachability_test(conn)) {
585 return; /* this was a test fetch. don't retry. */
587 if (!entry_list_is_constrained(get_options()))
588 router_set_status(conn->identity_digest, 0); /* don't try him again */
589 if (conn->_base.purpose == DIR_PURPOSE_FETCH_V2_NETWORKSTATUS) {
590 log_info(LD_DIR, "Giving up on directory server at '%s'; retrying",
591 conn->_base.address);
592 connection_dir_download_networkstatus_failed(conn, -1);
593 } else if (conn->_base.purpose == DIR_PURPOSE_FETCH_SERVERDESC ||
594 conn->_base.purpose == DIR_PURPOSE_FETCH_EXTRAINFO) {
595 log_info(LD_DIR, "Giving up on directory server at '%s'; retrying",
596 conn->_base.address);
597 if (conn->router_purpose == ROUTER_PURPOSE_BRIDGE)
598 connection_dir_bridge_routerdesc_failed(conn);
599 connection_dir_download_routerdesc_failed(conn);
600 } else if (conn->_base.purpose == DIR_PURPOSE_FETCH_CONSENSUS) {
601 networkstatus_consensus_download_failed(0);
602 } else if (conn->_base.purpose == DIR_PURPOSE_FETCH_CERTIFICATE) {
603 log_info(LD_DIR, "Giving up on directory server at '%s'; retrying",
604 conn->_base.address);
605 connection_dir_download_cert_failed(conn, 0);
606 } else if (conn->_base.purpose == DIR_PURPOSE_FETCH_DETACHED_SIGNATURES) {
607 log_info(LD_DIR, "Giving up downloading detached signatures from '%s'",
608 conn->_base.address);
609 } else if (conn->_base.purpose == DIR_PURPOSE_FETCH_STATUS_VOTE) {
610 log_info(LD_DIR, "Giving up downloading votes from '%s'",
611 conn->_base.address);
615 /** Called when an attempt to download one or more network status
616 * documents on connection <b>conn</b> failed. Decide whether to
617 * retry the fetch now, later, or never.
619 static void
620 connection_dir_download_networkstatus_failed(dir_connection_t *conn,
621 int status_code)
623 if (!conn->requested_resource) {
624 /* We never reached directory_send_command, which means that we never
625 * opened a network connection. Either we're out of sockets, or the
626 * network is down. Either way, retrying would be pointless. */
627 return;
629 if (!strcmpstart(conn->requested_resource, "all")) {
630 /* We're a non-authoritative directory cache; try again. Ignore status
631 * code, since we don't want to keep trying forever in a tight loop
632 * if all the authorities are shutting us out. */
633 smartlist_t *trusted_dirs = router_get_trusted_dir_servers();
634 SMARTLIST_FOREACH(trusted_dirs, trusted_dir_server_t *, ds,
635 download_status_failed(&ds->v2_ns_dl_status, 0));
636 directory_get_from_dirserver(conn->_base.purpose, conn->router_purpose,
637 "all.z", 0 /* don't retry_if_no_servers */);
638 } else if (!strcmpstart(conn->requested_resource, "fp/")) {
639 /* We were trying to download by fingerprint; mark them all as having
640 * failed, and possibly retry them later.*/
641 smartlist_t *failed = smartlist_create();
642 dir_split_resource_into_fingerprints(conn->requested_resource+3,
643 failed, NULL, 0);
644 if (smartlist_len(failed)) {
645 dir_networkstatus_download_failed(failed, status_code);
646 SMARTLIST_FOREACH(failed, char *, cp, tor_free(cp));
648 smartlist_free(failed);
652 /** Helper: Attempt to fetch directly the descriptors of each bridge
653 * listed in <b>failed</b>.
655 static void
656 connection_dir_retry_bridges(smartlist_t *descs)
658 char digest[DIGEST_LEN];
659 SMARTLIST_FOREACH(descs, const char *, cp,
661 if (base16_decode(digest, DIGEST_LEN, cp, strlen(cp))<0) {
662 log_warn(LD_BUG, "Malformed fingerprint in list: %s",
663 escaped(cp));
664 continue;
666 retry_bridge_descriptor_fetch_directly(digest);
670 /** Called when an attempt to download one or more router descriptors
671 * or extra-info documents on connection <b>conn</b> failed.
673 static void
674 connection_dir_download_routerdesc_failed(dir_connection_t *conn)
676 /* No need to increment the failure count for routerdescs, since
677 * it's not their fault. */
679 /* No need to relaunch descriptor downloads here: we already do it
680 * every 10 or 60 seconds (FOO_DESCRIPTOR_RETRY_INTERVAL) in main.c. */
681 tor_assert(conn->_base.purpose == DIR_PURPOSE_FETCH_SERVERDESC ||
682 conn->_base.purpose == DIR_PURPOSE_FETCH_EXTRAINFO);
684 (void) conn;
687 /** Called when an attempt to download a bridge's routerdesc from
688 * one of the authorities failed due to a network error. If
689 * possible attempt to download descriptors from the bridge directly.
691 static void
692 connection_dir_bridge_routerdesc_failed(dir_connection_t *conn)
694 smartlist_t *which = NULL;
696 /* Requests for bridge descriptors are in the form 'fp/', so ignore
697 anything else. */
698 if (!conn->requested_resource || strcmpstart(conn->requested_resource,"fp/"))
699 return;
701 which = smartlist_create();
702 dir_split_resource_into_fingerprints(conn->requested_resource
703 + strlen("fp/"),
704 which, NULL, 0);
706 tor_assert(conn->_base.purpose != DIR_PURPOSE_FETCH_EXTRAINFO);
707 if (smartlist_len(which)) {
708 connection_dir_retry_bridges(which);
709 SMARTLIST_FOREACH(which, char *, cp, tor_free(cp));
711 smartlist_free(which);
714 /** Called when an attempt to fetch a certificate fails. */
715 static void
716 connection_dir_download_cert_failed(dir_connection_t *conn, int status)
718 smartlist_t *failed;
719 tor_assert(conn->_base.purpose == DIR_PURPOSE_FETCH_CERTIFICATE);
721 if (!conn->requested_resource)
722 return;
723 failed = smartlist_create();
724 dir_split_resource_into_fingerprints(conn->requested_resource+3,
725 failed, NULL, DSR_HEX);
726 SMARTLIST_FOREACH(failed, char *, cp,
728 authority_cert_dl_failed(cp, status);
729 tor_free(cp);
731 smartlist_free(failed);
733 update_certificate_downloads(time(NULL));
736 /** Evaluate the situation and decide if we should use an encrypted
737 * "begindir-style" connection for this directory request.
738 * 1) If or_port is 0, or it's a direct conn and or_port is firewalled
739 * or we're a dir mirror, no.
740 * 2) If we prefer to avoid begindir conns, and we're not fetching or
741 * publishing a bridge relay descriptor, no.
742 * 3) Else yes.
744 static int
745 directory_command_should_use_begindir(or_options_t *options,
746 const tor_addr_t *addr,
747 int or_port, uint8_t router_purpose,
748 int anonymized_connection)
750 if (!or_port)
751 return 0; /* We don't know an ORPort -- no chance. */
752 if (!anonymized_connection)
753 if (!fascist_firewall_allows_address_or(addr, or_port) ||
754 directory_fetches_from_authorities(options) ||
755 (server_mode(options) && !options->Address))
756 return 0; /* We're firewalled or are acting like a relay -- also no. */
757 if (!options->TunnelDirConns &&
758 router_purpose != ROUTER_PURPOSE_BRIDGE)
759 return 0; /* We prefer to avoid using begindir conns. Fine. */
760 return 1;
763 /** Helper for directory_initiate_command_routerstatus: send the
764 * command to a server whose address is <b>address</b>, whose IP is
765 * <b>addr</b>, whose directory port is <b>dir_port</b>, whose tor version
766 * <b>supports_begindir</b>, and whose identity key digest is
767 * <b>digest</b>. */
768 void
769 directory_initiate_command(const char *address, const tor_addr_t *_addr,
770 uint16_t or_port, uint16_t dir_port,
771 int supports_conditional_consensus,
772 int supports_begindir, const char *digest,
773 uint8_t dir_purpose, uint8_t router_purpose,
774 int anonymized_connection, const char *resource,
775 const char *payload, size_t payload_len,
776 time_t if_modified_since)
778 directory_initiate_command_rend(address, _addr, or_port, dir_port,
779 supports_conditional_consensus,
780 supports_begindir, digest, dir_purpose,
781 router_purpose, anonymized_connection,
782 resource, payload, payload_len,
783 if_modified_since, NULL);
786 /** Same as directory_initiate_command(), but accepts rendezvous data to
787 * fetch a hidden service descriptor. */
788 static void
789 directory_initiate_command_rend(const char *address, const tor_addr_t *_addr,
790 uint16_t or_port, uint16_t dir_port,
791 int supports_conditional_consensus,
792 int supports_begindir, const char *digest,
793 uint8_t dir_purpose, uint8_t router_purpose,
794 int anonymized_connection,
795 const char *resource,
796 const char *payload, size_t payload_len,
797 time_t if_modified_since,
798 const rend_data_t *rend_query)
800 dir_connection_t *conn;
801 or_options_t *options = get_options();
802 int socket_error = 0;
803 int use_begindir = supports_begindir &&
804 directory_command_should_use_begindir(options, _addr,
805 or_port, router_purpose, anonymized_connection);
806 tor_addr_t addr;
808 tor_assert(address);
809 tor_assert(_addr);
810 tor_assert(or_port || dir_port);
811 tor_assert(digest);
813 tor_addr_copy(&addr, _addr);
815 log_debug(LD_DIR, "anonymized %d, use_begindir %d.",
816 anonymized_connection, use_begindir);
818 log_debug(LD_DIR, "Initiating %s", dir_conn_purpose_to_string(dir_purpose));
820 /* ensure that we don't make direct connections when a SOCKS server is
821 * configured. */
822 if (!anonymized_connection && !use_begindir && !options->HttpProxy &&
823 (options->Socks4Proxy || options->Socks5Proxy)) {
824 log_warn(LD_DIR, "Cannot connect to a directory server through a "
825 "SOCKS proxy!");
826 return;
829 conn = dir_connection_new(AF_INET);
831 /* set up conn so it's got all the data we need to remember */
832 tor_addr_copy(&conn->_base.addr, &addr);
833 conn->_base.port = use_begindir ? or_port : dir_port;
834 conn->_base.address = tor_strdup(address);
835 memcpy(conn->identity_digest, digest, DIGEST_LEN);
837 conn->_base.purpose = dir_purpose;
838 conn->router_purpose = router_purpose;
840 /* give it an initial state */
841 conn->_base.state = DIR_CONN_STATE_CONNECTING;
843 /* decide whether we can learn our IP address from this conn */
844 conn->dirconn_direct = !anonymized_connection;
846 /* copy rendezvous data, if any */
847 if (rend_query)
848 conn->rend_data = rend_data_dup(rend_query);
850 if (!anonymized_connection && !use_begindir) {
851 /* then we want to connect to dirport directly */
853 if (options->HttpProxy) {
854 tor_addr_copy(&addr, &options->HttpProxyAddr);
855 dir_port = options->HttpProxyPort;
858 switch (connection_connect(TO_CONN(conn), conn->_base.address, &addr,
859 dir_port, &socket_error)) {
860 case -1:
861 connection_dir_request_failed(conn); /* retry if we want */
862 /* XXX we only pass 'conn' above, not 'resource', 'payload',
863 * etc. So in many situations it can't retry! -RD */
864 connection_free(TO_CONN(conn));
865 return;
866 case 1:
867 /* start flushing conn */
868 conn->_base.state = DIR_CONN_STATE_CLIENT_SENDING;
869 /* fall through */
870 case 0:
871 /* queue the command on the outbuf */
872 directory_send_command(conn, dir_purpose, 1, resource,
873 payload, payload_len,
874 supports_conditional_consensus,
875 if_modified_since);
876 connection_watch_events(TO_CONN(conn), READ_EVENT | WRITE_EVENT);
877 /* writable indicates finish, readable indicates broken link,
878 error indicates broken link in windowsland. */
880 } else { /* we want to connect via a tor connection */
881 edge_connection_t *linked_conn;
883 /* If it's an anonymized connection, remember the fact that we
884 * wanted it for later: maybe we'll want it again soon. */
885 if (anonymized_connection && use_begindir)
886 rep_hist_note_used_internal(time(NULL), 0, 1);
887 else if (anonymized_connection && !use_begindir)
888 rep_hist_note_used_port(time(NULL), conn->_base.port);
890 /* make an AP connection
891 * populate it and add it at the right state
892 * hook up both sides
894 linked_conn =
895 connection_ap_make_link(conn->_base.address, conn->_base.port,
896 digest, use_begindir, conn->dirconn_direct);
897 if (!linked_conn) {
898 log_warn(LD_NET,"Making tunnel to dirserver failed.");
899 connection_mark_for_close(TO_CONN(conn));
900 return;
902 connection_link_connections(TO_CONN(conn), TO_CONN(linked_conn));
904 if (connection_add(TO_CONN(conn)) < 0) {
905 log_warn(LD_NET,"Unable to add connection for link to dirserver.");
906 connection_mark_for_close(TO_CONN(conn));
907 return;
909 conn->_base.state = DIR_CONN_STATE_CLIENT_SENDING;
910 /* queue the command on the outbuf */
911 directory_send_command(conn, dir_purpose, 0, resource,
912 payload, payload_len,
913 supports_conditional_consensus,
914 if_modified_since);
915 connection_watch_events(TO_CONN(conn), READ_EVENT|WRITE_EVENT);
916 connection_start_reading(TO_CONN(linked_conn));
920 /** Return true iff anything we say on <b>conn</b> is being encrypted before
921 * we send it to the client/server. */
923 connection_dir_is_encrypted(dir_connection_t *conn)
925 /* Right now it's sufficient to see if conn is or has been linked, since
926 * the only thing it could be linked to is an edge connection on a
927 * circuit, and the only way it could have been unlinked is at the edge
928 * connection getting closed.
930 return TO_CONN(conn)->linked;
933 /** Helper for sorting
935 * sort strings alphabetically
937 static int
938 _compare_strs(const void **a, const void **b)
940 const char *s1 = *a, *s2 = *b;
941 return strcmp(s1, s2);
944 #define CONDITIONAL_CONSENSUS_FPR_LEN 3
945 #if (CONDITIONAL_CONSENSUS_FPR_LEN > DIGEST_LEN)
946 #error "conditional consensus fingerprint length is larger than digest length"
947 #endif
949 /** Return the URL we should use for a consensus download.
951 * This url depends on whether or not the server we go to
952 * is sufficiently new to support conditional consensus downloading,
953 * i.e. GET .../consensus/<b>fpr</b>+<b>fpr</b>+<b>fpr</b>
955 static char *
956 directory_get_consensus_url(int supports_conditional_consensus)
958 char *url;
959 size_t len;
961 if (supports_conditional_consensus) {
962 char *authority_id_list;
963 smartlist_t *authority_digests = smartlist_create();
965 SMARTLIST_FOREACH(router_get_trusted_dir_servers(),
966 trusted_dir_server_t *, ds,
968 char *hex;
969 if (!(ds->type & V3_AUTHORITY))
970 continue;
972 hex = tor_malloc(2*CONDITIONAL_CONSENSUS_FPR_LEN+1);
973 base16_encode(hex, 2*CONDITIONAL_CONSENSUS_FPR_LEN+1,
974 ds->v3_identity_digest, CONDITIONAL_CONSENSUS_FPR_LEN);
975 smartlist_add(authority_digests, hex);
977 smartlist_sort(authority_digests, _compare_strs);
978 authority_id_list = smartlist_join_strings(authority_digests,
979 "+", 0, NULL);
981 len = strlen(authority_id_list)+64;
982 url = tor_malloc(len);
983 tor_snprintf(url, len, "/tor/status-vote/current/consensus/%s.z",
984 authority_id_list);
986 SMARTLIST_FOREACH(authority_digests, char *, cp, tor_free(cp));
987 smartlist_free(authority_digests);
988 tor_free(authority_id_list);
989 } else {
990 url = tor_strdup("/tor/status-vote/current/consensus.z");
992 return url;
995 /** Queue an appropriate HTTP command on conn-\>outbuf. The other args
996 * are as in directory_initiate_command().
998 static void
999 directory_send_command(dir_connection_t *conn,
1000 int purpose, int direct, const char *resource,
1001 const char *payload, size_t payload_len,
1002 int supports_conditional_consensus,
1003 time_t if_modified_since)
1005 char proxystring[256];
1006 char proxyauthstring[256];
1007 char hoststring[128];
1008 char imsstring[RFC1123_TIME_LEN+32];
1009 char *url;
1010 char request[8192];
1011 const char *httpcommand = NULL;
1012 size_t len;
1014 tor_assert(conn);
1015 tor_assert(conn->_base.type == CONN_TYPE_DIR);
1017 tor_free(conn->requested_resource);
1018 if (resource)
1019 conn->requested_resource = tor_strdup(resource);
1021 /* come up with a string for which Host: we want */
1022 if (conn->_base.port == 80) {
1023 strlcpy(hoststring, conn->_base.address, sizeof(hoststring));
1024 } else {
1025 tor_snprintf(hoststring, sizeof(hoststring),"%s:%d",
1026 conn->_base.address, conn->_base.port);
1029 /* Format if-modified-since */
1030 if (!if_modified_since) {
1031 imsstring[0] = '\0';
1032 } else {
1033 char b[RFC1123_TIME_LEN+1];
1034 format_rfc1123_time(b, if_modified_since);
1035 tor_snprintf(imsstring, sizeof(imsstring), "\r\nIf-Modified-Since: %s", b);
1038 /* come up with some proxy lines, if we're using one. */
1039 if (direct && get_options()->HttpProxy) {
1040 char *base64_authenticator=NULL;
1041 const char *authenticator = get_options()->HttpProxyAuthenticator;
1043 tor_snprintf(proxystring, sizeof(proxystring),"http://%s", hoststring);
1044 if (authenticator) {
1045 base64_authenticator = alloc_http_authenticator(authenticator);
1046 if (!base64_authenticator)
1047 log_warn(LD_BUG, "Encoding http authenticator failed");
1049 if (base64_authenticator) {
1050 tor_snprintf(proxyauthstring, sizeof(proxyauthstring),
1051 "\r\nProxy-Authorization: Basic %s",
1052 base64_authenticator);
1053 tor_free(base64_authenticator);
1054 } else {
1055 proxyauthstring[0] = 0;
1057 } else {
1058 proxystring[0] = 0;
1059 proxyauthstring[0] = 0;
1062 switch (purpose) {
1063 case DIR_PURPOSE_FETCH_V2_NETWORKSTATUS:
1064 tor_assert(resource);
1065 httpcommand = "GET";
1066 len = strlen(resource)+32;
1067 url = tor_malloc(len);
1068 tor_snprintf(url, len, "/tor/status/%s", resource);
1069 break;
1070 case DIR_PURPOSE_FETCH_CONSENSUS:
1071 tor_assert(!resource);
1072 tor_assert(!payload);
1073 httpcommand = "GET";
1074 url = directory_get_consensus_url(supports_conditional_consensus);
1075 log_info(LD_DIR, "Downloading consensus from %s using %s",
1076 hoststring, url);
1077 break;
1078 case DIR_PURPOSE_FETCH_CERTIFICATE:
1079 tor_assert(resource);
1080 tor_assert(!payload);
1081 httpcommand = "GET";
1082 len = strlen(resource)+32;
1083 url = tor_malloc(len);
1084 tor_snprintf(url, len, "/tor/keys/%s", resource);
1085 break;
1086 case DIR_PURPOSE_FETCH_STATUS_VOTE:
1087 tor_assert(resource);
1088 tor_assert(!payload);
1089 httpcommand = "GET";
1090 len = strlen(resource)+32;
1091 url = tor_malloc(len);
1092 tor_snprintf(url, len, "/tor/status-vote/next/%s.z", resource);
1093 break;
1094 case DIR_PURPOSE_FETCH_DETACHED_SIGNATURES:
1095 tor_assert(!resource);
1096 tor_assert(!payload);
1097 httpcommand = "GET";
1098 url = tor_strdup("/tor/status-vote/next/consensus-signatures.z");
1099 break;
1100 case DIR_PURPOSE_FETCH_SERVERDESC:
1101 tor_assert(resource);
1102 httpcommand = "GET";
1103 len = strlen(resource)+32;
1104 url = tor_malloc(len);
1105 tor_snprintf(url, len, "/tor/server/%s", resource);
1106 break;
1107 case DIR_PURPOSE_FETCH_EXTRAINFO:
1108 tor_assert(resource);
1109 httpcommand = "GET";
1110 len = strlen(resource)+32;
1111 url = tor_malloc(len);
1112 tor_snprintf(url, len, "/tor/extra/%s", resource);
1113 break;
1114 case DIR_PURPOSE_UPLOAD_DIR:
1115 tor_assert(!resource);
1116 tor_assert(payload);
1117 httpcommand = "POST";
1118 url = tor_strdup("/tor/");
1119 break;
1120 case DIR_PURPOSE_UPLOAD_VOTE:
1121 tor_assert(!resource);
1122 tor_assert(payload);
1123 httpcommand = "POST";
1124 url = tor_strdup("/tor/post/vote");
1125 break;
1126 case DIR_PURPOSE_UPLOAD_SIGNATURES:
1127 tor_assert(!resource);
1128 tor_assert(payload);
1129 httpcommand = "POST";
1130 url = tor_strdup("/tor/post/consensus-signature");
1131 break;
1132 case DIR_PURPOSE_FETCH_RENDDESC_V2:
1133 tor_assert(resource);
1134 tor_assert(strlen(resource) <= REND_DESC_ID_V2_LEN_BASE32);
1135 tor_assert(!payload);
1136 httpcommand = "GET";
1137 len = strlen(resource) + 32;
1138 url = tor_malloc(len);
1139 tor_snprintf(url, len, "/tor/rendezvous2/%s", resource);
1140 break;
1141 case DIR_PURPOSE_UPLOAD_RENDDESC:
1142 tor_assert(!resource);
1143 tor_assert(payload);
1144 httpcommand = "POST";
1145 url = tor_strdup("/tor/rendezvous/publish");
1146 break;
1147 case DIR_PURPOSE_UPLOAD_RENDDESC_V2:
1148 tor_assert(!resource);
1149 tor_assert(payload);
1150 httpcommand = "POST";
1151 url = tor_strdup("/tor/rendezvous2/publish");
1152 break;
1153 default:
1154 tor_assert(0);
1155 return;
1158 if (strlen(proxystring) + strlen(url) >= 4096) {
1159 log_warn(LD_BUG,
1160 "Squid does not like URLs longer than 4095 bytes, and this "
1161 "one is %d bytes long: %s%s",
1162 (int)(strlen(proxystring) + strlen(url)), proxystring, url);
1165 tor_snprintf(request, sizeof(request), "%s %s", httpcommand, proxystring);
1166 connection_write_to_buf(request, strlen(request), TO_CONN(conn));
1167 connection_write_to_buf(url, strlen(url), TO_CONN(conn));
1168 tor_free(url);
1170 if (!strcmp(httpcommand, "GET") && !payload) {
1171 tor_snprintf(request, sizeof(request),
1172 " HTTP/1.0\r\nHost: %s%s%s\r\n\r\n",
1173 hoststring,
1174 imsstring,
1175 proxyauthstring);
1176 } else {
1177 tor_snprintf(request, sizeof(request),
1178 " HTTP/1.0\r\nContent-Length: %lu\r\nHost: %s%s%s\r\n\r\n",
1179 payload ? (unsigned long)payload_len : 0,
1180 hoststring,
1181 imsstring,
1182 proxyauthstring);
1184 connection_write_to_buf(request, strlen(request), TO_CONN(conn));
1186 if (payload) {
1187 /* then send the payload afterwards too */
1188 connection_write_to_buf(payload, payload_len, TO_CONN(conn));
1192 /** Parse an HTTP request string <b>headers</b> of the form
1193 * \verbatim
1194 * "\%s [http[s]://]\%s HTTP/1..."
1195 * \endverbatim
1196 * If it's well-formed, strdup the second \%s into *<b>url</b>, and
1197 * nul-terminate it. If the url doesn't start with "/tor/", rewrite it
1198 * so it does. Return 0.
1199 * Otherwise, return -1.
1201 static int
1202 parse_http_url(const char *headers, char **url)
1204 char *s, *start, *tmp;
1206 s = (char *)eat_whitespace_no_nl(headers);
1207 if (!*s) return -1;
1208 s = (char *)find_whitespace(s); /* get past GET/POST */
1209 if (!*s) return -1;
1210 s = (char *)eat_whitespace_no_nl(s);
1211 if (!*s) return -1;
1212 start = s; /* this is it, assuming it's valid */
1213 s = (char *)find_whitespace(start);
1214 if (!*s) return -1;
1216 /* tolerate the http[s] proxy style of putting the hostname in the url */
1217 if (s-start >= 4 && !strcmpstart(start,"http")) {
1218 tmp = start + 4;
1219 if (*tmp == 's')
1220 tmp++;
1221 if (s-tmp >= 3 && !strcmpstart(tmp,"://")) {
1222 tmp = strchr(tmp+3, '/');
1223 if (tmp && tmp < s) {
1224 log_debug(LD_DIR,"Skipping over 'http[s]://hostname/' string");
1225 start = tmp;
1230 if (s-start < 5 || strcmpstart(start,"/tor/")) { /* need to rewrite it */
1231 *url = tor_malloc(s - start + 5);
1232 strlcpy(*url,"/tor", s-start+5);
1233 strlcat((*url)+4, start, s-start+1);
1234 } else {
1235 *url = tor_strndup(start, s-start);
1237 return 0;
1240 /** Return a copy of the first HTTP header in <b>headers</b> whose key is
1241 * <b>which</b>. The key should be given with a terminating colon and space;
1242 * this function copies everything after, up to but not including the
1243 * following \\r\\n. */
1244 static char *
1245 http_get_header(const char *headers, const char *which)
1247 const char *cp = headers;
1248 while (cp) {
1249 if (!strcasecmpstart(cp, which)) {
1250 char *eos;
1251 cp += strlen(which);
1252 if ((eos = strchr(cp,'\r')))
1253 return tor_strndup(cp, eos-cp);
1254 else
1255 return tor_strdup(cp);
1257 cp = strchr(cp, '\n');
1258 if (cp)
1259 ++cp;
1261 return NULL;
1264 /** If <b>headers</b> indicates that a proxy was involved, then rewrite
1265 * <b>conn</b>-\>address to describe our best guess of the address that
1266 * originated this HTTP request. */
1267 static void
1268 http_set_address_origin(const char *headers, connection_t *conn)
1270 char *fwd;
1272 fwd = http_get_header(headers, "Forwarded-For: ");
1273 if (!fwd)
1274 fwd = http_get_header(headers, "X-Forwarded-For: ");
1275 if (fwd) {
1276 struct in_addr in;
1277 if (!tor_inet_aton(fwd, &in) || is_internal_IP(ntohl(in.s_addr), 0)) {
1278 log_debug(LD_DIR, "Ignoring unrecognized or internal IP %s",
1279 escaped(fwd));
1280 tor_free(fwd);
1281 return;
1283 tor_free(conn->address);
1284 conn->address = tor_strdup(fwd);
1285 tor_free(fwd);
1289 /** Parse an HTTP response string <b>headers</b> of the form
1290 * \verbatim
1291 * "HTTP/1.\%d \%d\%s\r\n...".
1292 * \endverbatim
1294 * If it's well-formed, assign the status code to *<b>code</b> and
1295 * return 0. Otherwise, return -1.
1297 * On success: If <b>date</b> is provided, set *date to the Date
1298 * header in the http headers, or 0 if no such header is found. If
1299 * <b>compression</b> is provided, set *<b>compression</b> to the
1300 * compression method given in the Content-Encoding header, or 0 if no
1301 * such header is found, or -1 if the value of the header is not
1302 * recognized. If <b>reason</b> is provided, strdup the reason string
1303 * into it.
1306 parse_http_response(const char *headers, int *code, time_t *date,
1307 compress_method_t *compression, char **reason)
1309 unsigned n1, n2;
1310 char datestr[RFC1123_TIME_LEN+1];
1311 smartlist_t *parsed_headers;
1312 tor_assert(headers);
1313 tor_assert(code);
1315 while (TOR_ISSPACE(*headers)) headers++; /* tolerate leading whitespace */
1317 if (tor_sscanf(headers, "HTTP/1.%u %u", &n1, &n2) < 2 ||
1318 (n1 != 0 && n1 != 1) ||
1319 (n2 < 100 || n2 >= 600)) {
1320 log_warn(LD_HTTP,"Failed to parse header %s",escaped(headers));
1321 return -1;
1323 *code = n2;
1325 parsed_headers = smartlist_create();
1326 smartlist_split_string(parsed_headers, headers, "\n",
1327 SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
1328 if (reason) {
1329 smartlist_t *status_line_elements = smartlist_create();
1330 tor_assert(smartlist_len(parsed_headers));
1331 smartlist_split_string(status_line_elements,
1332 smartlist_get(parsed_headers, 0),
1333 " ", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 3);
1334 tor_assert(smartlist_len(status_line_elements) <= 3);
1335 if (smartlist_len(status_line_elements) == 3) {
1336 *reason = smartlist_get(status_line_elements, 2);
1337 smartlist_set(status_line_elements, 2, NULL); /* Prevent free */
1339 SMARTLIST_FOREACH(status_line_elements, char *, cp, tor_free(cp));
1340 smartlist_free(status_line_elements);
1342 if (date) {
1343 *date = 0;
1344 SMARTLIST_FOREACH(parsed_headers, const char *, s,
1345 if (!strcmpstart(s, "Date: ")) {
1346 strlcpy(datestr, s+6, sizeof(datestr));
1347 /* This will do nothing on failure, so we don't need to check
1348 the result. We shouldn't warn, since there are many other valid
1349 date formats besides the one we use. */
1350 parse_rfc1123_time(datestr, date);
1351 break;
1354 if (compression) {
1355 const char *enc = NULL;
1356 SMARTLIST_FOREACH(parsed_headers, const char *, s,
1357 if (!strcmpstart(s, "Content-Encoding: ")) {
1358 enc = s+18; break;
1360 if (!enc || !strcmp(enc, "identity")) {
1361 *compression = NO_METHOD;
1362 } else if (!strcmp(enc, "deflate") || !strcmp(enc, "x-deflate")) {
1363 *compression = ZLIB_METHOD;
1364 } else if (!strcmp(enc, "gzip") || !strcmp(enc, "x-gzip")) {
1365 *compression = GZIP_METHOD;
1366 } else {
1367 log_info(LD_HTTP, "Unrecognized content encoding: %s. Trying to deal.",
1368 escaped(enc));
1369 *compression = UNKNOWN_METHOD;
1372 SMARTLIST_FOREACH(parsed_headers, char *, s, tor_free(s));
1373 smartlist_free(parsed_headers);
1375 return 0;
1378 /** Return true iff <b>body</b> doesn't start with a plausible router or
1379 * running-list or directory opening. This is a sign of possible compression.
1381 static int
1382 body_is_plausible(const char *body, size_t len, int purpose)
1384 int i;
1385 if (len == 0)
1386 return 1; /* empty bodies don't need decompression */
1387 if (len < 32)
1388 return 0;
1389 if (purpose != DIR_PURPOSE_FETCH_RENDDESC) {
1390 if (!strcmpstart(body,"router") ||
1391 !strcmpstart(body,"signed-directory") ||
1392 !strcmpstart(body,"network-status") ||
1393 !strcmpstart(body,"running-routers"))
1394 return 1;
1395 for (i=0;i<32;++i) {
1396 if (!TOR_ISPRINT(body[i]) && !TOR_ISSPACE(body[i]))
1397 return 0;
1399 return 1;
1400 } else {
1401 return 1;
1405 /** Called when we've just fetched a bunch of router descriptors in
1406 * <b>body</b>. The list <b>which</b>, if present, holds digests for
1407 * descriptors we requested: descriptor digests if <b>descriptor_digests</b>
1408 * is true, or identity digests otherwise. Parse the descriptors, validate
1409 * them, and annotate them as having purpose <b>purpose</b> and as having been
1410 * downloaded from <b>source</b>.
1412 * Return the number of routers actually added. */
1413 static int
1414 load_downloaded_routers(const char *body, smartlist_t *which,
1415 int descriptor_digests,
1416 int router_purpose,
1417 const char *source)
1419 char buf[256];
1420 char time_buf[ISO_TIME_LEN+1];
1421 int added = 0;
1422 int general = router_purpose == ROUTER_PURPOSE_GENERAL;
1423 format_iso_time(time_buf, time(NULL));
1424 tor_assert(source);
1426 if (tor_snprintf(buf, sizeof(buf),
1427 "@downloaded-at %s\n"
1428 "@source %s\n"
1429 "%s%s%s", time_buf, escaped(source),
1430 !general ? "@purpose " : "",
1431 !general ? router_purpose_to_string(router_purpose) : "",
1432 !general ? "\n" : "")<0)
1433 return added;
1435 added = router_load_routers_from_string(body, NULL, SAVED_NOWHERE, which,
1436 descriptor_digests, buf);
1437 control_event_bootstrap(BOOTSTRAP_STATUS_LOADING_DESCRIPTORS,
1438 count_loading_descriptors_progress());
1439 return added;
1442 /** We are a client, and we've finished reading the server's
1443 * response. Parse it and act appropriately.
1445 * If we're still happy with using this directory server in the future, return
1446 * 0. Otherwise return -1; and the caller should consider trying the request
1447 * again.
1449 * The caller will take care of marking the connection for close.
1451 static int
1452 connection_dir_client_reached_eof(dir_connection_t *conn)
1454 char *body;
1455 char *headers;
1456 char *reason = NULL;
1457 size_t body_len=0, orig_len=0;
1458 int status_code;
1459 time_t date_header=0;
1460 long delta;
1461 compress_method_t compression;
1462 int plausible;
1463 int skewed=0;
1464 int allow_partial = (conn->_base.purpose == DIR_PURPOSE_FETCH_SERVERDESC ||
1465 conn->_base.purpose == DIR_PURPOSE_FETCH_EXTRAINFO);
1466 int was_compressed=0;
1467 time_t now = time(NULL);
1469 switch (fetch_from_buf_http(conn->_base.inbuf,
1470 &headers, MAX_HEADERS_SIZE,
1471 &body, &body_len, MAX_DIR_DL_SIZE,
1472 allow_partial)) {
1473 case -1: /* overflow */
1474 log_warn(LD_PROTOCOL,
1475 "'fetch' response too large (server '%s:%d'). Closing.",
1476 conn->_base.address, conn->_base.port);
1477 return -1;
1478 case 0:
1479 log_info(LD_HTTP,
1480 "'fetch' response not all here, but we're at eof. Closing.");
1481 return -1;
1482 /* case 1, fall through */
1484 orig_len = body_len;
1486 if (parse_http_response(headers, &status_code, &date_header,
1487 &compression, &reason) < 0) {
1488 log_warn(LD_HTTP,"Unparseable headers (server '%s:%d'). Closing.",
1489 conn->_base.address, conn->_base.port);
1490 tor_free(body); tor_free(headers);
1491 return -1;
1493 if (!reason) reason = tor_strdup("[no reason given]");
1495 log_debug(LD_DIR,
1496 "Received response from directory server '%s:%d': %d %s",
1497 conn->_base.address, conn->_base.port, status_code,
1498 escaped(reason));
1500 /* now check if it's got any hints for us about our IP address. */
1501 if (conn->dirconn_direct) {
1502 char *guess = http_get_header(headers, X_ADDRESS_HEADER);
1503 if (guess) {
1504 router_new_address_suggestion(guess, conn);
1505 tor_free(guess);
1509 if (date_header > 0) {
1510 /* The date header was written very soon after we sent our request,
1511 * so compute the skew as the difference between sending the request
1512 * and the date header. (We used to check now-date_header, but that's
1513 * inaccurate if we spend a lot of time downloading.)
1515 delta = conn->_base.timestamp_lastwritten - date_header;
1516 if (labs(delta)>ALLOW_DIRECTORY_TIME_SKEW) {
1517 char dbuf[64];
1518 int trusted = router_digest_is_trusted_dir(conn->identity_digest);
1519 format_time_interval(dbuf, sizeof(dbuf), delta);
1520 log_fn(trusted ? LOG_WARN : LOG_INFO,
1521 LD_HTTP,
1522 "Received directory with skewed time (server '%s:%d'): "
1523 "It seems that our clock is %s by %s, or that theirs is %s. "
1524 "Tor requires an accurate clock to work: please check your time, "
1525 "timezone, and date settings.",
1526 conn->_base.address, conn->_base.port,
1527 delta>0 ? "ahead" : "behind", dbuf,
1528 delta>0 ? "behind" : "ahead");
1529 skewed = 1; /* don't check the recommended-versions line */
1530 control_event_general_status(trusted ? LOG_WARN : LOG_NOTICE,
1531 "CLOCK_SKEW SKEW=%ld SOURCE=DIRSERV:%s:%d",
1532 delta, conn->_base.address, conn->_base.port);
1533 } else {
1534 log_debug(LD_HTTP, "Time on received directory is within tolerance; "
1535 "we are %ld seconds skewed. (That's okay.)", delta);
1538 (void) skewed; /* skewed isn't used yet. */
1540 if (status_code == 503) {
1541 if (body_len < 16) {
1542 routerstatus_t *rs;
1543 trusted_dir_server_t *ds;
1544 log_info(LD_DIR,"Received http status code %d (%s) from server "
1545 "'%s:%d'. I'll try again soon.",
1546 status_code, escaped(reason), conn->_base.address,
1547 conn->_base.port);
1548 if ((rs = router_get_consensus_status_by_id(conn->identity_digest)))
1549 rs->last_dir_503_at = now;
1550 if ((ds = router_get_trusteddirserver_by_digest(conn->identity_digest)))
1551 ds->fake_status.last_dir_503_at = now;
1553 tor_free(body); tor_free(headers); tor_free(reason);
1554 return -1;
1556 /* XXXX022 Remove this once every server with bug 539 is obsolete. */
1557 log_info(LD_DIR, "Server at '%s:%d' sent us a 503 response, but included "
1558 "a body anyway. We'll pretend it gave us a 200.",
1559 conn->_base.address, conn->_base.port);
1560 status_code = 200;
1563 plausible = body_is_plausible(body, body_len, conn->_base.purpose);
1564 if (compression != NO_METHOD || !plausible) {
1565 char *new_body = NULL;
1566 size_t new_len = 0;
1567 compress_method_t guessed = detect_compression_method(body, body_len);
1568 if (compression == UNKNOWN_METHOD || guessed != compression) {
1569 /* Tell the user if we don't believe what we're told about compression.*/
1570 const char *description1, *description2;
1571 if (compression == ZLIB_METHOD)
1572 description1 = "as deflated";
1573 else if (compression == GZIP_METHOD)
1574 description1 = "as gzipped";
1575 else if (compression == NO_METHOD)
1576 description1 = "as uncompressed";
1577 else
1578 description1 = "with an unknown Content-Encoding";
1579 if (guessed == ZLIB_METHOD)
1580 description2 = "deflated";
1581 else if (guessed == GZIP_METHOD)
1582 description2 = "gzipped";
1583 else if (!plausible)
1584 description2 = "confusing binary junk";
1585 else
1586 description2 = "uncompressed";
1588 log_info(LD_HTTP, "HTTP body from server '%s:%d' was labeled %s, "
1589 "but it seems to be %s.%s",
1590 conn->_base.address, conn->_base.port, description1,
1591 description2,
1592 (compression>0 && guessed>0)?" Trying both.":"");
1594 /* Try declared compression first if we can. */
1595 if (compression == GZIP_METHOD || compression == ZLIB_METHOD)
1596 tor_gzip_uncompress(&new_body, &new_len, body, body_len, compression,
1597 !allow_partial, LOG_PROTOCOL_WARN);
1598 /* Okay, if that didn't work, and we think that it was compressed
1599 * differently, try that. */
1600 if (!new_body &&
1601 (guessed == GZIP_METHOD || guessed == ZLIB_METHOD) &&
1602 compression != guessed)
1603 tor_gzip_uncompress(&new_body, &new_len, body, body_len, guessed,
1604 !allow_partial, LOG_PROTOCOL_WARN);
1605 /* If we're pretty sure that we have a compressed directory, and
1606 * we didn't manage to uncompress it, then warn and bail. */
1607 if (!plausible && !new_body) {
1608 log_fn(LOG_PROTOCOL_WARN, LD_HTTP,
1609 "Unable to decompress HTTP body (server '%s:%d').",
1610 conn->_base.address, conn->_base.port);
1611 tor_free(body); tor_free(headers); tor_free(reason);
1612 return -1;
1614 if (new_body) {
1615 tor_free(body);
1616 body = new_body;
1617 body_len = new_len;
1618 was_compressed = 1;
1622 if (conn->_base.purpose == DIR_PURPOSE_FETCH_V2_NETWORKSTATUS) {
1623 smartlist_t *which = NULL;
1624 v2_networkstatus_source_t source;
1625 char *cp;
1626 log_info(LD_DIR,"Received networkstatus objects (size %d) from server "
1627 "'%s:%d'", (int)body_len, conn->_base.address, conn->_base.port);
1628 if (status_code != 200) {
1629 log_warn(LD_DIR,
1630 "Received http status code %d (%s) from server "
1631 "'%s:%d' while fetching \"/tor/status/%s\". I'll try again soon.",
1632 status_code, escaped(reason), conn->_base.address,
1633 conn->_base.port, conn->requested_resource);
1634 tor_free(body); tor_free(headers); tor_free(reason);
1635 connection_dir_download_networkstatus_failed(conn, status_code);
1636 return -1;
1638 if (conn->requested_resource &&
1639 !strcmpstart(conn->requested_resource,"fp/")) {
1640 source = NS_FROM_DIR_BY_FP;
1641 which = smartlist_create();
1642 dir_split_resource_into_fingerprints(conn->requested_resource+3,
1643 which, NULL, 0);
1644 } else if (conn->requested_resource &&
1645 !strcmpstart(conn->requested_resource, "all")) {
1646 source = NS_FROM_DIR_ALL;
1647 which = smartlist_create();
1648 SMARTLIST_FOREACH(router_get_trusted_dir_servers(),
1649 trusted_dir_server_t *, ds,
1651 char *hex = tor_malloc(HEX_DIGEST_LEN+1);
1652 base16_encode(hex, HEX_DIGEST_LEN+1, ds->digest, DIGEST_LEN);
1653 smartlist_add(which, hex);
1655 } else {
1656 /* XXXX Can we even end up here? -- weasel*/
1657 source = NS_FROM_DIR_BY_FP;
1658 log_warn(LD_BUG, "We received a networkstatus but we didn't ask "
1659 "for it by fp, nor did we ask for all.");
1661 cp = body;
1662 while (*cp) {
1663 char *next = strstr(cp, "\nnetwork-status-version");
1664 if (next)
1665 next[1] = '\0';
1666 /* learn from it, and then remove it from 'which' */
1667 if (router_set_networkstatus_v2(cp, now, source, which)<0)
1668 break;
1669 if (next) {
1670 next[1] = 'n';
1671 cp = next+1;
1672 } else
1673 break;
1675 /* launches router downloads as needed */
1676 routers_update_all_from_networkstatus(now, 2);
1677 directory_info_has_arrived(now, 0);
1678 if (which) {
1679 if (smartlist_len(which)) {
1680 dir_networkstatus_download_failed(which, status_code);
1682 SMARTLIST_FOREACH(which, char *, s, tor_free(s));
1683 smartlist_free(which);
1687 if (conn->_base.purpose == DIR_PURPOSE_FETCH_CONSENSUS) {
1688 int r;
1689 if (status_code != 200) {
1690 int severity = (status_code == 304) ? LOG_INFO : LOG_WARN;
1691 log(severity, LD_DIR,
1692 "Received http status code %d (%s) from server "
1693 "'%s:%d' while fetching consensus directory.",
1694 status_code, escaped(reason), conn->_base.address,
1695 conn->_base.port);
1696 tor_free(body); tor_free(headers); tor_free(reason);
1697 networkstatus_consensus_download_failed(status_code);
1698 return -1;
1700 log_info(LD_DIR,"Received consensus directory (size %d) from server "
1701 "'%s:%d'", (int)body_len, conn->_base.address, conn->_base.port);
1702 if ((r=networkstatus_set_current_consensus(body, "ns", 0))<0) {
1703 log_fn(r<-1?LOG_WARN:LOG_INFO, LD_DIR,
1704 "Unable to load consensus directory downloaded from "
1705 "server '%s:%d'. I'll try again soon.",
1706 conn->_base.address, conn->_base.port);
1707 tor_free(body); tor_free(headers); tor_free(reason);
1708 networkstatus_consensus_download_failed(0);
1709 return -1;
1711 /* launches router downloads as needed */
1712 routers_update_all_from_networkstatus(now, 3);
1713 directory_info_has_arrived(now, 0);
1714 log_info(LD_DIR, "Successfully loaded consensus.");
1717 if (conn->_base.purpose == DIR_PURPOSE_FETCH_CERTIFICATE) {
1718 if (status_code != 200) {
1719 log_warn(LD_DIR,
1720 "Received http status code %d (%s) from server "
1721 "'%s:%d' while fetching \"/tor/keys/%s\".",
1722 status_code, escaped(reason), conn->_base.address,
1723 conn->_base.port, conn->requested_resource);
1724 connection_dir_download_cert_failed(conn, status_code);
1725 tor_free(body); tor_free(headers); tor_free(reason);
1726 return -1;
1728 log_info(LD_DIR,"Received authority certificates (size %d) from server "
1729 "'%s:%d'", (int)body_len, conn->_base.address, conn->_base.port);
1730 if (trusted_dirs_load_certs_from_string(body, 0, 1)<0) {
1731 log_warn(LD_DIR, "Unable to parse fetched certificates");
1732 /* if we fetched more than one and only some failed, the successful
1733 * ones got flushed to disk so it's safe to call this on them */
1734 connection_dir_download_cert_failed(conn, status_code);
1735 } else {
1736 directory_info_has_arrived(now, 0);
1737 log_info(LD_DIR, "Successfully loaded certificates from fetch.");
1740 if (conn->_base.purpose == DIR_PURPOSE_FETCH_STATUS_VOTE) {
1741 const char *msg;
1742 int st;
1743 log_info(LD_DIR,"Got votes (size %d) from server %s:%d",
1744 (int)body_len, conn->_base.address, conn->_base.port);
1745 if (status_code != 200) {
1746 log_warn(LD_DIR,
1747 "Received http status code %d (%s) from server "
1748 "'%s:%d' while fetching \"/tor/status-vote/next/%s.z\".",
1749 status_code, escaped(reason), conn->_base.address,
1750 conn->_base.port, conn->requested_resource);
1751 tor_free(body); tor_free(headers); tor_free(reason);
1752 return -1;
1754 dirvote_add_vote(body, &msg, &st);
1755 if (st > 299) {
1756 log_warn(LD_DIR, "Error adding retrieved vote: %s", msg);
1757 } else {
1758 log_info(LD_DIR, "Added vote(s) successfully [msg: %s]", msg);
1761 if (conn->_base.purpose == DIR_PURPOSE_FETCH_DETACHED_SIGNATURES) {
1762 const char *msg = NULL;
1763 log_info(LD_DIR,"Got detached signatures (size %d) from server %s:%d",
1764 (int)body_len, conn->_base.address, conn->_base.port);
1765 if (status_code != 200) {
1766 log_warn(LD_DIR,
1767 "Received http status code %d (%s) from server '%s:%d' while fetching "
1768 "\"/tor/status-vote/next/consensus-signatures.z\".",
1769 status_code, escaped(reason), conn->_base.address,
1770 conn->_base.port);
1771 tor_free(body); tor_free(headers); tor_free(reason);
1772 return -1;
1774 if (dirvote_add_signatures(body, conn->_base.address, &msg)<0) {
1775 log_warn(LD_DIR, "Problem adding detached signatures from %s:%d: %s",
1776 conn->_base.address, conn->_base.port, msg?msg:"???");
1780 if (conn->_base.purpose == DIR_PURPOSE_FETCH_SERVERDESC ||
1781 conn->_base.purpose == DIR_PURPOSE_FETCH_EXTRAINFO) {
1782 int was_ei = conn->_base.purpose == DIR_PURPOSE_FETCH_EXTRAINFO;
1783 smartlist_t *which = NULL;
1784 int n_asked_for = 0;
1785 int descriptor_digests = conn->requested_resource &&
1786 !strcmpstart(conn->requested_resource,"d/");
1787 log_info(LD_DIR,"Received %s (size %d) from server '%s:%d'",
1788 was_ei ? "extra server info" : "server info",
1789 (int)body_len, conn->_base.address, conn->_base.port);
1790 if (conn->requested_resource &&
1791 (!strcmpstart(conn->requested_resource,"d/") ||
1792 !strcmpstart(conn->requested_resource,"fp/"))) {
1793 which = smartlist_create();
1794 dir_split_resource_into_fingerprints(conn->requested_resource +
1795 (descriptor_digests ? 2 : 3),
1796 which, NULL, 0);
1797 n_asked_for = smartlist_len(which);
1799 if (status_code != 200) {
1800 int dir_okay = status_code == 404 ||
1801 (status_code == 400 && !strcmp(reason, "Servers unavailable."));
1802 /* 404 means that it didn't have them; no big deal.
1803 * Older (pre-0.1.1.8) servers said 400 Servers unavailable instead. */
1804 log_fn(dir_okay ? LOG_INFO : LOG_WARN, LD_DIR,
1805 "Received http status code %d (%s) from server '%s:%d' "
1806 "while fetching \"/tor/server/%s\". I'll try again soon.",
1807 status_code, escaped(reason), conn->_base.address,
1808 conn->_base.port, conn->requested_resource);
1809 if (!which) {
1810 connection_dir_download_routerdesc_failed(conn);
1811 } else {
1812 dir_routerdesc_download_failed(which, status_code,
1813 conn->router_purpose,
1814 was_ei, descriptor_digests);
1815 SMARTLIST_FOREACH(which, char *, cp, tor_free(cp));
1816 smartlist_free(which);
1818 tor_free(body); tor_free(headers); tor_free(reason);
1819 return dir_okay ? 0 : -1;
1821 /* Learn the routers, assuming we requested by fingerprint or "all"
1822 * or "authority".
1824 * We use "authority" to fetch our own descriptor for
1825 * testing, and to fetch bridge descriptors for bootstrapping. Ignore
1826 * the output of "authority" requests unless we are using bridges,
1827 * since otherwise they'll be the response from reachability tests,
1828 * and we don't really want to add that to our routerlist. */
1829 if (which || (conn->requested_resource &&
1830 (!strcmpstart(conn->requested_resource, "all") ||
1831 (!strcmpstart(conn->requested_resource, "authority") &&
1832 get_options()->UseBridges)))) {
1833 /* as we learn from them, we remove them from 'which' */
1834 if (was_ei) {
1835 router_load_extrainfo_from_string(body, NULL, SAVED_NOWHERE, which,
1836 descriptor_digests);
1837 } else {
1838 //router_load_routers_from_string(body, NULL, SAVED_NOWHERE, which,
1839 // descriptor_digests, conn->router_purpose);
1840 if (load_downloaded_routers(body, which, descriptor_digests,
1841 conn->router_purpose,
1842 conn->_base.address))
1843 directory_info_has_arrived(now, 0);
1846 if (which) { /* mark remaining ones as failed */
1847 log_info(LD_DIR, "Received %d/%d %s requested from %s:%d",
1848 n_asked_for-smartlist_len(which), n_asked_for,
1849 was_ei ? "extra-info documents" : "router descriptors",
1850 conn->_base.address, (int)conn->_base.port);
1851 if (smartlist_len(which)) {
1852 dir_routerdesc_download_failed(which, status_code,
1853 conn->router_purpose,
1854 was_ei, descriptor_digests);
1856 SMARTLIST_FOREACH(which, char *, cp, tor_free(cp));
1857 smartlist_free(which);
1859 if (directory_conn_is_self_reachability_test(conn))
1860 router_dirport_found_reachable();
1863 if (conn->_base.purpose == DIR_PURPOSE_UPLOAD_DIR) {
1864 switch (status_code) {
1865 case 200: {
1866 trusted_dir_server_t *ds =
1867 router_get_trusteddirserver_by_digest(conn->identity_digest);
1868 char *rejected_hdr = http_get_header(headers,
1869 "X-Descriptor-Not-New: ");
1870 int rejected = 0;
1871 if (rejected_hdr) {
1872 if (!strcmp(rejected_hdr, "Yes")) {
1873 log_info(LD_GENERAL,
1874 "Authority '%s' declined our descriptor (not new)",
1875 ds->nickname);
1876 /* XXXX use this information; be sure to upload next one
1877 * sooner. -NM */
1878 /* XXXX021 On further thought, the task above implies that we're
1879 * basing our regenerate-descriptor time on when we uploaded the
1880 * last descriptor, not on the published time of the last
1881 * descriptor. If those are different, that's a bad thing to
1882 * do. -NM */
1883 rejected = 1;
1885 tor_free(rejected_hdr);
1887 log_info(LD_GENERAL,"eof (status 200) after uploading server "
1888 "descriptor: finished.");
1889 control_event_server_status(
1890 LOG_NOTICE, "ACCEPTED_SERVER_DESCRIPTOR DIRAUTH=%s:%d",
1891 conn->_base.address, conn->_base.port);
1893 ds->has_accepted_serverdesc = 1;
1894 if (directories_have_accepted_server_descriptor())
1895 control_event_server_status(LOG_NOTICE, "GOOD_SERVER_DESCRIPTOR");
1897 break;
1898 case 400:
1899 log_warn(LD_GENERAL,"http status 400 (%s) response from "
1900 "dirserver '%s:%d'. Please correct.",
1901 escaped(reason), conn->_base.address, conn->_base.port);
1902 control_event_server_status(LOG_WARN,
1903 "BAD_SERVER_DESCRIPTOR DIRAUTH=%s:%d REASON=\"%s\"",
1904 conn->_base.address, conn->_base.port, escaped(reason));
1905 break;
1906 default:
1907 log_warn(LD_GENERAL,
1908 "http status %d (%s) reason unexpected while uploading "
1909 "descriptor to server '%s:%d').",
1910 status_code, escaped(reason), conn->_base.address,
1911 conn->_base.port);
1912 break;
1914 /* return 0 in all cases, since we don't want to mark any
1915 * dirservers down just because they don't like us. */
1918 if (conn->_base.purpose == DIR_PURPOSE_UPLOAD_VOTE) {
1919 switch (status_code) {
1920 case 200: {
1921 log_notice(LD_DIR,"Uploaded a vote to dirserver %s:%d",
1922 conn->_base.address, conn->_base.port);
1924 break;
1925 case 400:
1926 log_warn(LD_DIR,"http status 400 (%s) response after uploading "
1927 "vote to dirserver '%s:%d'. Please correct.",
1928 escaped(reason), conn->_base.address, conn->_base.port);
1929 break;
1930 default:
1931 log_warn(LD_GENERAL,
1932 "http status %d (%s) reason unexpected while uploading "
1933 "vote to server '%s:%d').",
1934 status_code, escaped(reason), conn->_base.address,
1935 conn->_base.port);
1936 break;
1938 /* return 0 in all cases, since we don't want to mark any
1939 * dirservers down just because they don't like us. */
1942 if (conn->_base.purpose == DIR_PURPOSE_UPLOAD_SIGNATURES) {
1943 switch (status_code) {
1944 case 200: {
1945 log_notice(LD_DIR,"Uploaded signature(s) to dirserver %s:%d",
1946 conn->_base.address, conn->_base.port);
1948 break;
1949 case 400:
1950 log_warn(LD_DIR,"http status 400 (%s) response after uploading "
1951 "signatures to dirserver '%s:%d'. Please correct.",
1952 escaped(reason), conn->_base.address, conn->_base.port);
1953 break;
1954 default:
1955 log_warn(LD_GENERAL,
1956 "http status %d (%s) reason unexpected while uploading "
1957 "signatures to server '%s:%d').",
1958 status_code, escaped(reason), conn->_base.address,
1959 conn->_base.port);
1960 break;
1962 /* return 0 in all cases, since we don't want to mark any
1963 * dirservers down just because they don't like us. */
1966 if (conn->_base.purpose == DIR_PURPOSE_FETCH_RENDDESC) {
1967 tor_assert(conn->rend_data);
1968 log_info(LD_REND,"Received rendezvous descriptor (size %d, status %d "
1969 "(%s))",
1970 (int)body_len, status_code, escaped(reason));
1971 switch (status_code) {
1972 case 200:
1973 if (rend_cache_store(body, body_len, 0) < -1) {
1974 log_warn(LD_REND,"Failed to parse rendezvous descriptor.");
1975 /* Any pending rendezvous attempts will notice when
1976 * connection_about_to_close_connection()
1977 * cleans this dir conn up. */
1978 /* We could retry. But since v0 descriptors are going out of
1979 * style, it isn't worth the hassle. We'll do better in v2. */
1980 } else {
1981 /* Success, or at least there's a v2 descriptor already
1982 * present. Notify pending connections about this. */
1983 conn->_base.purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC;
1984 rend_client_desc_trynow(conn->rend_data->onion_address);
1986 break;
1987 case 404:
1988 /* Not there. Pending connections will be notified when
1989 * connection_about_to_close_connection() cleans this conn up. */
1990 break;
1991 case 400:
1992 log_warn(LD_REND,
1993 "http status 400 (%s). Dirserver didn't like our "
1994 "rendezvous query?", escaped(reason));
1995 break;
1996 default:
1997 log_warn(LD_REND,"http status %d (%s) response unexpected while "
1998 "fetching hidden service descriptor (server '%s:%d').",
1999 status_code, escaped(reason), conn->_base.address,
2000 conn->_base.port);
2001 break;
2005 if (conn->_base.purpose == DIR_PURPOSE_FETCH_RENDDESC_V2) {
2006 tor_assert(conn->rend_data);
2007 log_info(LD_REND,"Received rendezvous descriptor (size %d, status %d "
2008 "(%s))",
2009 (int)body_len, status_code, escaped(reason));
2010 switch (status_code) {
2011 case 200:
2012 switch (rend_cache_store_v2_desc_as_client(body, conn->rend_data)) {
2013 case -2:
2014 log_warn(LD_REND,"Fetching v2 rendezvous descriptor failed. "
2015 "Retrying at another directory.");
2016 /* We'll retry when connection_about_to_close_connection()
2017 * cleans this dir conn up. */
2018 break;
2019 case -1:
2020 /* We already have a v0 descriptor here. Ignoring this one
2021 * and _not_ performing another request. */
2022 log_info(LD_REND, "Successfully fetched v2 rendezvous "
2023 "descriptor, but we already have a v0 descriptor.");
2024 conn->_base.purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC;
2025 break;
2026 default:
2027 /* success. notify pending connections about this. */
2028 log_info(LD_REND, "Successfully fetched v2 rendezvous "
2029 "descriptor.");
2030 conn->_base.purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC;
2031 rend_client_desc_trynow(conn->rend_data->onion_address);
2032 break;
2034 break;
2035 case 404:
2036 /* Not there. We'll retry when
2037 * connection_about_to_close_connection() cleans this conn up. */
2038 log_info(LD_REND,"Fetching v2 rendezvous descriptor failed: "
2039 "Retrying at another directory.");
2040 break;
2041 case 400:
2042 log_warn(LD_REND, "Fetching v2 rendezvous descriptor failed: "
2043 "http status 400 (%s). Dirserver didn't like our "
2044 "v2 rendezvous query? Retrying at another directory.",
2045 escaped(reason));
2046 break;
2047 default:
2048 log_warn(LD_REND, "Fetching v2 rendezvous descriptor failed: "
2049 "http status %d (%s) response unexpected while "
2050 "fetching v2 hidden service descriptor (server '%s:%d'). "
2051 "Retrying at another directory.",
2052 status_code, escaped(reason), conn->_base.address,
2053 conn->_base.port);
2054 break;
2058 if (conn->_base.purpose == DIR_PURPOSE_UPLOAD_RENDDESC ||
2059 conn->_base.purpose == DIR_PURPOSE_UPLOAD_RENDDESC_V2) {
2060 log_info(LD_REND,"Uploaded rendezvous descriptor (status %d "
2061 "(%s))",
2062 status_code, escaped(reason));
2063 switch (status_code) {
2064 case 200:
2065 log_info(LD_REND,
2066 "Uploading rendezvous descriptor: finished with status "
2067 "200 (%s)", escaped(reason));
2068 break;
2069 case 400:
2070 log_warn(LD_REND,"http status 400 (%s) response from dirserver "
2071 "'%s:%d'. Malformed rendezvous descriptor?",
2072 escaped(reason), conn->_base.address, conn->_base.port);
2073 break;
2074 default:
2075 log_warn(LD_REND,"http status %d (%s) response unexpected (server "
2076 "'%s:%d').",
2077 status_code, escaped(reason), conn->_base.address,
2078 conn->_base.port);
2079 break;
2082 note_client_request(conn->_base.purpose, was_compressed, orig_len);
2083 tor_free(body); tor_free(headers); tor_free(reason);
2084 return 0;
2087 /** Called when a directory connection reaches EOF. */
2089 connection_dir_reached_eof(dir_connection_t *conn)
2091 int retval;
2092 if (conn->_base.state != DIR_CONN_STATE_CLIENT_READING) {
2093 log_info(LD_HTTP,"conn reached eof, not reading. [state=%d] Closing.",
2094 conn->_base.state);
2095 connection_close_immediate(TO_CONN(conn)); /* error: give up on flushing */
2096 connection_mark_for_close(TO_CONN(conn));
2097 return -1;
2100 retval = connection_dir_client_reached_eof(conn);
2101 if (retval == 0) /* success */
2102 conn->_base.state = DIR_CONN_STATE_CLIENT_FINISHED;
2103 connection_mark_for_close(TO_CONN(conn));
2104 return retval;
2107 /** If any directory object is arriving, and it's over 10MB large, we're
2108 * getting DoS'd. (As of 0.1.2.x, raw directories are about 1MB, and we never
2109 * ask for more than 96 router descriptors at a time.)
2111 #define MAX_DIRECTORY_OBJECT_SIZE (10*(1<<20))
2113 /** Read handler for directory connections. (That's connections <em>to</em>
2114 * directory servers and connections <em>at</em> directory servers.)
2117 connection_dir_process_inbuf(dir_connection_t *conn)
2119 tor_assert(conn);
2120 tor_assert(conn->_base.type == CONN_TYPE_DIR);
2122 /* Directory clients write, then read data until they receive EOF;
2123 * directory servers read data until they get an HTTP command, then
2124 * write their response (when it's finished flushing, they mark for
2125 * close).
2128 /* If we're on the dirserver side, look for a command. */
2129 if (conn->_base.state == DIR_CONN_STATE_SERVER_COMMAND_WAIT) {
2130 if (directory_handle_command(conn) < 0) {
2131 connection_mark_for_close(TO_CONN(conn));
2132 return -1;
2134 return 0;
2137 if (buf_datalen(conn->_base.inbuf) > MAX_DIRECTORY_OBJECT_SIZE) {
2138 log_warn(LD_HTTP, "Too much data received from directory connection: "
2139 "denial of service attempt, or you need to upgrade?");
2140 connection_mark_for_close(TO_CONN(conn));
2141 return -1;
2144 if (!conn->_base.inbuf_reached_eof)
2145 log_debug(LD_HTTP,"Got data, not eof. Leaving on inbuf.");
2146 return 0;
2149 /** Create an http response for the client <b>conn</b> out of
2150 * <b>status</b> and <b>reason_phrase</b>. Write it to <b>conn</b>.
2152 static void
2153 write_http_status_line(dir_connection_t *conn, int status,
2154 const char *reason_phrase)
2156 char buf[256];
2157 if (tor_snprintf(buf, sizeof(buf), "HTTP/1.0 %d %s\r\n\r\n",
2158 status, reason_phrase ? reason_phrase : "OK") < 0) {
2159 log_warn(LD_BUG,"status line too long.");
2160 return;
2162 connection_write_to_buf(buf, strlen(buf), TO_CONN(conn));
2165 /** Write the header for an HTTP/1.0 response onto <b>conn</b>-\>outbuf,
2166 * with <b>type</b> as the Content-Type.
2168 * If <b>length</b> is nonnegative, it is the Content-Length.
2169 * If <b>encoding</b> is provided, it is the Content-Encoding.
2170 * If <b>cache_lifetime</b> is greater than 0, the content may be cached for
2171 * up to cache_lifetime seconds. Otherwise, the content may not be cached. */
2172 static void
2173 write_http_response_header_impl(dir_connection_t *conn, ssize_t length,
2174 const char *type, const char *encoding,
2175 const char *extra_headers,
2176 long cache_lifetime)
2178 char date[RFC1123_TIME_LEN+1];
2179 char tmp[1024];
2180 char *cp;
2181 time_t now = time(NULL);
2183 tor_assert(conn);
2185 format_rfc1123_time(date, now);
2186 cp = tmp;
2187 tor_snprintf(cp, sizeof(tmp),
2188 "HTTP/1.0 200 OK\r\nDate: %s\r\n",
2189 date);
2190 cp += strlen(tmp);
2191 if (type) {
2192 tor_snprintf(cp, sizeof(tmp)-(cp-tmp), "Content-Type: %s\r\n", type);
2193 cp += strlen(cp);
2195 if (!is_local_addr(&conn->_base.addr)) {
2196 /* Don't report the source address for a nearby/private connection.
2197 * Otherwise we tend to mis-report in cases where incoming ports are
2198 * being forwarded to a Tor server running behind the firewall. */
2199 tor_snprintf(cp, sizeof(tmp)-(cp-tmp),
2200 X_ADDRESS_HEADER "%s\r\n", conn->_base.address);
2201 cp += strlen(cp);
2203 if (encoding) {
2204 tor_snprintf(cp, sizeof(tmp)-(cp-tmp),
2205 "Content-Encoding: %s\r\n", encoding);
2206 cp += strlen(cp);
2208 if (length >= 0) {
2209 tor_snprintf(cp, sizeof(tmp)-(cp-tmp),
2210 "Content-Length: %ld\r\n", (long)length);
2211 cp += strlen(cp);
2213 if (cache_lifetime > 0) {
2214 char expbuf[RFC1123_TIME_LEN+1];
2215 format_rfc1123_time(expbuf, now + cache_lifetime);
2216 /* We could say 'Cache-control: max-age=%d' here if we start doing
2217 * http/1.1 */
2218 tor_snprintf(cp, sizeof(tmp)-(cp-tmp),
2219 "Expires: %s\r\n", expbuf);
2220 cp += strlen(cp);
2221 } else if (cache_lifetime == 0) {
2222 /* We could say 'Cache-control: no-cache' here if we start doing
2223 * http/1.1 */
2224 strlcpy(cp, "Pragma: no-cache\r\n", sizeof(tmp)-(cp-tmp));
2225 cp += strlen(cp);
2227 if (extra_headers) {
2228 strlcpy(cp, extra_headers, sizeof(tmp)-(cp-tmp));
2229 cp += strlen(cp);
2231 if (sizeof(tmp)-(cp-tmp) > 3)
2232 memcpy(cp, "\r\n", 3);
2233 else
2234 tor_assert(0);
2235 connection_write_to_buf(tmp, strlen(tmp), TO_CONN(conn));
2238 /** As write_http_response_header_impl, but sets encoding and content-typed
2239 * based on whether the response will be <b>compressed</b> or not. */
2240 static void
2241 write_http_response_header(dir_connection_t *conn, ssize_t length,
2242 int compressed, long cache_lifetime)
2244 write_http_response_header_impl(conn, length,
2245 compressed?"application/octet-stream":"text/plain",
2246 compressed?"deflate":"identity",
2247 NULL,
2248 cache_lifetime);
2251 #ifdef INSTRUMENT_DOWNLOADS
2252 typedef struct request_t {
2253 uint64_t bytes; /**< How many bytes have we transferred? */
2254 uint64_t count; /**< How many requests have we made? */
2255 } request_t;
2257 /** Map used to keep track of how much data we've up/downloaded in what kind
2258 * of request. Maps from request type to pointer to request_t. */
2259 static strmap_t *request_map = NULL;
2261 /** Record that a client request of <b>purpose</b> was made, and that
2262 * <b>bytes</b> bytes of possibly <b>compressed</b> data were sent/received.
2263 * Used to keep track of how much we've up/downloaded in what kind of
2264 * request. */
2265 static void
2266 note_client_request(int purpose, int compressed, size_t bytes)
2268 char *key;
2269 const char *kind = NULL;
2270 switch (purpose) {
2271 case DIR_PURPOSE_FETCH_V2_NETWORKSTATUS: kind = "dl/status"; break;
2272 case DIR_PURPOSE_FETCH_CONSENSUS: kind = "dl/consensus"; break;
2273 case DIR_PURPOSE_FETCH_CERTIFICATE: kind = "dl/cert"; break;
2274 case DIR_PURPOSE_FETCH_STATUS_VOTE: kind = "dl/vote"; break;
2275 case DIR_PURPOSE_FETCH_DETACHED_SIGNATURES: kind = "dl/detached_sig";
2276 break;
2277 case DIR_PURPOSE_FETCH_SERVERDESC: kind = "dl/server"; break;
2278 case DIR_PURPOSE_FETCH_EXTRAINFO: kind = "dl/extra"; break;
2279 case DIR_PURPOSE_UPLOAD_DIR: kind = "dl/ul-dir"; break;
2280 case DIR_PURPOSE_UPLOAD_VOTE: kind = "dl/ul-vote"; break;
2281 case DIR_PURPOSE_UPLOAD_SIGNATURES: kind = "dl/ul-sig"; break;
2282 case DIR_PURPOSE_FETCH_RENDDESC: kind = "dl/rend"; break;
2283 case DIR_PURPOSE_FETCH_RENDDESC_V2: kind = "dl/rend2"; break;
2284 case DIR_PURPOSE_UPLOAD_RENDDESC: kind = "dl/ul-rend"; break;
2285 case DIR_PURPOSE_UPLOAD_RENDDESC_V2: kind = "dl/ul-rend2"; break;
2287 if (kind) {
2288 key = tor_malloc(256);
2289 tor_snprintf(key, 256, "%s%s", kind, compressed?".z":"");
2290 } else {
2291 key = tor_malloc(256);
2292 tor_snprintf(key, 256, "unknown purpose (%d)%s",
2293 purpose, compressed?".z":"");
2295 note_request(key, bytes);
2296 tor_free(key);
2299 /** Helper: initialize the request map to instrument downloads. */
2300 static void
2301 ensure_request_map_initialized(void)
2303 if (!request_map)
2304 request_map = strmap_new();
2307 /** Called when we just transmitted or received <b>bytes</b> worth of data
2308 * because of a request of type <b>key</b> (an arbitrary identifier): adds
2309 * <b>bytes</b> to the total associated with key. */
2310 void
2311 note_request(const char *key, size_t bytes)
2313 request_t *r;
2314 ensure_request_map_initialized();
2316 r = strmap_get(request_map, key);
2317 if (!r) {
2318 r = tor_malloc_zero(sizeof(request_t));
2319 strmap_set(request_map, key, r);
2321 r->bytes += bytes;
2322 r->count++;
2325 /** Return a newly allocated string holding a summary of bytes used per
2326 * request type. */
2327 char *
2328 directory_dump_request_log(void)
2330 smartlist_t *lines;
2331 char tmp[256];
2332 char *result;
2333 strmap_iter_t *iter;
2335 ensure_request_map_initialized();
2337 lines = smartlist_create();
2339 for (iter = strmap_iter_init(request_map);
2340 !strmap_iter_done(iter);
2341 iter = strmap_iter_next(request_map, iter)) {
2342 const char *key;
2343 void *val;
2344 request_t *r;
2345 strmap_iter_get(iter, &key, &val);
2346 r = val;
2347 tor_snprintf(tmp, sizeof(tmp), "%s "U64_FORMAT" "U64_FORMAT"\n",
2348 key, U64_PRINTF_ARG(r->bytes), U64_PRINTF_ARG(r->count));
2349 smartlist_add(lines, tor_strdup(tmp));
2351 smartlist_sort_strings(lines);
2352 result = smartlist_join_strings(lines, "", 0, NULL);
2353 SMARTLIST_FOREACH(lines, char *, cp, tor_free(cp));
2354 smartlist_free(lines);
2355 return result;
2357 #else
2358 static void
2359 note_client_request(int purpose, int compressed, size_t bytes)
2361 (void)purpose;
2362 (void)compressed;
2363 (void)bytes;
2366 void
2367 note_request(const char *key, size_t bytes)
2369 (void)key;
2370 (void)bytes;
2373 char *
2374 directory_dump_request_log(void)
2376 return tor_strdup("Not supported.");
2378 #endif
2380 /** Decide whether a client would accept the consensus we have.
2382 * Clients can say they only want a consensus if it's signed by more
2383 * than half the authorities in a list. They pass this list in
2384 * the url as "...consensus/<b>fpr</b>+<b>fpr</b>+<b>fpr</b>".
2386 * <b>fpr</b> may be an abbreviated fingerprint, i.e. only a left substring
2387 * of the full authority identity digest. (Only strings of even length,
2388 * i.e. encodings of full bytes, are handled correctly. In the case
2389 * of an odd number of hex digits the last one is silently ignored.)
2391 * Returns 1 if more than half of the requested authorities signed the
2392 * consensus, 0 otherwise.
2395 client_likes_consensus(networkstatus_t *v, const char *want_url)
2397 smartlist_t *want_authorities = smartlist_create();
2398 int need_at_least;
2399 int have = 0;
2401 dir_split_resource_into_fingerprints(want_url, want_authorities, NULL, 0);
2402 need_at_least = smartlist_len(want_authorities)/2+1;
2403 SMARTLIST_FOREACH_BEGIN(want_authorities, const char *, d) {
2404 char want_digest[DIGEST_LEN];
2405 size_t want_len = strlen(d)/2;
2406 if (want_len > DIGEST_LEN)
2407 want_len = DIGEST_LEN;
2409 if (base16_decode(want_digest, DIGEST_LEN, d, want_len*2) < 0) {
2410 log_fn(LOG_PROTOCOL_WARN, LD_DIR,
2411 "Failed to decode requested authority digest %s.", d);
2412 continue;
2415 SMARTLIST_FOREACH_BEGIN(v->voters, networkstatus_voter_info_t *, vi) {
2416 if (smartlist_len(vi->sigs) &&
2417 !memcmp(vi->identity_digest, want_digest, want_len)) {
2418 have++;
2419 break;
2421 } SMARTLIST_FOREACH_END(vi);
2423 /* early exit, if we already have enough */
2424 if (have >= need_at_least)
2425 break;
2426 } SMARTLIST_FOREACH_END(d);
2428 SMARTLIST_FOREACH(want_authorities, char *, d, tor_free(d));
2429 smartlist_free(want_authorities);
2430 return (have >= need_at_least);
2433 /** Helper function: called when a dirserver gets a complete HTTP GET
2434 * request. Look for a request for a directory or for a rendezvous
2435 * service descriptor. On finding one, write a response into
2436 * conn-\>outbuf. If the request is unrecognized, send a 400.
2437 * Always return 0. */
2438 static int
2439 directory_handle_command_get(dir_connection_t *conn, const char *headers,
2440 const char *body, size_t body_len)
2442 size_t dlen;
2443 char *url, *url_mem, *header;
2444 or_options_t *options = get_options();
2445 time_t if_modified_since = 0;
2446 int compressed;
2447 size_t url_len;
2449 /* We ignore the body of a GET request. */
2450 (void)body;
2451 (void)body_len;
2453 log_debug(LD_DIRSERV,"Received GET command.");
2455 conn->_base.state = DIR_CONN_STATE_SERVER_WRITING;
2457 if (parse_http_url(headers, &url) < 0) {
2458 write_http_status_line(conn, 400, "Bad request");
2459 return 0;
2461 if ((header = http_get_header(headers, "If-Modified-Since: "))) {
2462 struct tm tm;
2463 if (parse_http_time(header, &tm) == 0) {
2464 if_modified_since = tor_timegm(&tm);
2466 /* The correct behavior on a malformed If-Modified-Since header is to
2467 * act as if no If-Modified-Since header had been given. */
2468 tor_free(header);
2470 log_debug(LD_DIRSERV,"rewritten url as '%s'.", url);
2472 url_mem = url;
2473 url_len = strlen(url);
2474 compressed = url_len > 2 && !strcmp(url+url_len-2, ".z");
2475 if (compressed) {
2476 url[url_len-2] = '\0';
2477 url_len -= 2;
2480 if (!strcmp(url,"/tor/")) {
2481 const char *frontpage = get_dirportfrontpage();
2483 if (frontpage) {
2484 dlen = strlen(frontpage);
2485 /* Let's return a disclaimer page (users shouldn't use V1 anymore,
2486 and caches don't fetch '/', so this is safe). */
2488 /* [We don't check for write_bucket_low here, since we want to serve
2489 * this page no matter what.] */
2490 note_request(url, dlen);
2491 write_http_response_header_impl(conn, dlen, "text/html", "identity",
2492 NULL, DIRPORTFRONTPAGE_CACHE_LIFETIME);
2493 connection_write_to_buf(frontpage, dlen, TO_CONN(conn));
2494 goto done;
2496 /* if no disclaimer file, fall through and continue */
2499 if (!strcmp(url,"/tor/") || !strcmp(url,"/tor/dir")) { /* v1 dir fetch */
2500 cached_dir_t *d = dirserv_get_directory();
2502 if (!d) {
2503 log_info(LD_DIRSERV,"Client asked for the mirrored directory, but we "
2504 "don't have a good one yet. Sending 503 Dir not available.");
2505 write_http_status_line(conn, 503, "Directory unavailable");
2506 goto done;
2508 if (d->published < if_modified_since) {
2509 write_http_status_line(conn, 304, "Not modified");
2510 goto done;
2513 dlen = compressed ? d->dir_z_len : d->dir_len;
2515 if (global_write_bucket_low(TO_CONN(conn), dlen, 1)) {
2516 log_debug(LD_DIRSERV,
2517 "Client asked for the mirrored directory, but we've been "
2518 "writing too many bytes lately. Sending 503 Dir busy.");
2519 write_http_status_line(conn, 503, "Directory busy, try again later");
2520 goto done;
2523 note_request(url, dlen);
2525 log_debug(LD_DIRSERV,"Dumping %sdirectory to client.",
2526 compressed?"compressed ":"");
2527 write_http_response_header(conn, dlen, compressed,
2528 FULL_DIR_CACHE_LIFETIME);
2529 conn->cached_dir = d;
2530 conn->cached_dir_offset = 0;
2531 if (!compressed)
2532 conn->zlib_state = tor_zlib_new(0, ZLIB_METHOD);
2533 ++d->refcnt;
2535 /* Prime the connection with some data. */
2536 conn->dir_spool_src = DIR_SPOOL_CACHED_DIR;
2537 connection_dirserv_flushed_some(conn);
2538 goto done;
2541 if (!strcmp(url,"/tor/running-routers")) { /* running-routers fetch */
2542 cached_dir_t *d = dirserv_get_runningrouters();
2543 if (!d) {
2544 write_http_status_line(conn, 503, "Directory unavailable");
2545 goto done;
2547 if (d->published < if_modified_since) {
2548 write_http_status_line(conn, 304, "Not modified");
2549 goto done;
2551 dlen = compressed ? d->dir_z_len : d->dir_len;
2553 if (global_write_bucket_low(TO_CONN(conn), dlen, 1)) {
2554 log_info(LD_DIRSERV,
2555 "Client asked for running-routers, but we've been "
2556 "writing too many bytes lately. Sending 503 Dir busy.");
2557 write_http_status_line(conn, 503, "Directory busy, try again later");
2558 goto done;
2560 note_request(url, dlen);
2561 write_http_response_header(conn, dlen, compressed,
2562 RUNNINGROUTERS_CACHE_LIFETIME);
2563 connection_write_to_buf(compressed ? d->dir_z : d->dir, dlen,
2564 TO_CONN(conn));
2565 goto done;
2568 if (!strcmpstart(url,"/tor/status/")
2569 || !strcmpstart(url, "/tor/status-vote/current/consensus")) {
2570 /* v2 or v3 network status fetch. */
2571 smartlist_t *dir_fps = smartlist_create();
2572 int is_v3 = !strcmpstart(url, "/tor/status-vote");
2573 geoip_client_action_t act =
2574 is_v3 ? GEOIP_CLIENT_NETWORKSTATUS : GEOIP_CLIENT_NETWORKSTATUS_V2;
2575 const char *request_type = NULL;
2576 const char *key = url + strlen("/tor/status/");
2577 long lifetime = NETWORKSTATUS_CACHE_LIFETIME;
2579 if (!is_v3) {
2580 dirserv_get_networkstatus_v2_fingerprints(dir_fps, key);
2581 if (!strcmpstart(key, "fp/"))
2582 request_type = compressed?"/tor/status/fp.z":"/tor/status/fp";
2583 else if (!strcmpstart(key, "authority"))
2584 request_type = compressed?"/tor/status/authority.z":
2585 "/tor/status/authority";
2586 else if (!strcmpstart(key, "all"))
2587 request_type = compressed?"/tor/status/all.z":"/tor/status/all";
2588 else
2589 request_type = "/tor/status/?";
2590 } else {
2591 networkstatus_t *v = networkstatus_get_latest_consensus();
2592 time_t now = time(NULL);
2593 const char *want_fps = NULL;
2594 char *flavor = NULL;
2595 #define CONSENSUS_URL_PREFIX "/tor/status-vote/current/consensus/"
2596 #define CONSENSUS_FLAVORED_PREFIX "/tor/status-vote/current/consensus-"
2597 /* figure out the flavor if any, and who we wanted to sign the thing */
2598 if (!strcmpstart(url, CONSENSUS_FLAVORED_PREFIX)) {
2599 const char *f, *cp;
2600 f = url + strlen(CONSENSUS_FLAVORED_PREFIX);
2601 cp = strchr(f, '/');
2602 if (cp) {
2603 want_fps = cp+1;
2604 flavor = tor_strndup(f, cp-f);
2605 } else {
2606 flavor = tor_strdup(f);
2608 } else {
2609 if (!strcmpstart(url, CONSENSUS_URL_PREFIX))
2610 want_fps = url+strlen(CONSENSUS_URL_PREFIX);
2613 /* XXXX MICRODESC NM NM should check document of correct flavor */
2614 if (v && want_fps &&
2615 !client_likes_consensus(v, want_fps)) {
2616 write_http_status_line(conn, 404, "Consensus not signed by sufficient "
2617 "number of requested authorities");
2618 smartlist_free(dir_fps);
2619 geoip_note_ns_response(act, GEOIP_REJECT_NOT_ENOUGH_SIGS);
2620 tor_free(flavor);
2621 goto done;
2625 char *fp = tor_malloc_zero(DIGEST_LEN);
2626 if (flavor)
2627 strlcpy(fp, flavor, DIGEST_LEN);
2628 tor_free(flavor);
2629 smartlist_add(dir_fps, fp);
2631 request_type = compressed?"v3.z":"v3";
2632 lifetime = (v && v->fresh_until > now) ? v->fresh_until - now : 0;
2635 if (!smartlist_len(dir_fps)) { /* we failed to create/cache cp */
2636 write_http_status_line(conn, 503, "Network status object unavailable");
2637 smartlist_free(dir_fps);
2638 geoip_note_ns_response(act, GEOIP_REJECT_UNAVAILABLE);
2639 goto done;
2642 if (!dirserv_remove_old_statuses(dir_fps, if_modified_since)) {
2643 write_http_status_line(conn, 404, "Not found");
2644 SMARTLIST_FOREACH(dir_fps, char *, cp, tor_free(cp));
2645 smartlist_free(dir_fps);
2646 geoip_note_ns_response(act, GEOIP_REJECT_NOT_FOUND);
2647 goto done;
2648 } else if (!smartlist_len(dir_fps)) {
2649 write_http_status_line(conn, 304, "Not modified");
2650 SMARTLIST_FOREACH(dir_fps, char *, cp, tor_free(cp));
2651 smartlist_free(dir_fps);
2652 geoip_note_ns_response(act, GEOIP_REJECT_NOT_MODIFIED);
2653 goto done;
2656 dlen = dirserv_estimate_data_size(dir_fps, 0, compressed);
2657 if (global_write_bucket_low(TO_CONN(conn), dlen, 2)) {
2658 log_debug(LD_DIRSERV,
2659 "Client asked for network status lists, but we've been "
2660 "writing too many bytes lately. Sending 503 Dir busy.");
2661 write_http_status_line(conn, 503, "Directory busy, try again later");
2662 SMARTLIST_FOREACH(dir_fps, char *, fp, tor_free(fp));
2663 smartlist_free(dir_fps);
2664 geoip_note_ns_response(act, GEOIP_REJECT_BUSY);
2665 goto done;
2669 struct in_addr in;
2670 if (tor_inet_aton((TO_CONN(conn))->address, &in)) {
2671 geoip_note_client_seen(act, ntohl(in.s_addr), time(NULL));
2672 geoip_note_ns_response(act, GEOIP_SUCCESS);
2673 /* Note that a request for a network status has started, so that we
2674 * can measure the download time later on. */
2675 if (TO_CONN(conn)->dirreq_id)
2676 geoip_start_dirreq(TO_CONN(conn)->dirreq_id, dlen, act,
2677 DIRREQ_TUNNELED);
2678 else
2679 geoip_start_dirreq(TO_CONN(conn)->global_identifier, dlen, act,
2680 DIRREQ_DIRECT);
2684 // note_request(request_type,dlen);
2685 (void) request_type;
2686 write_http_response_header(conn, -1, compressed,
2687 smartlist_len(dir_fps) == 1 ? lifetime : 0);
2688 conn->fingerprint_stack = dir_fps;
2689 if (! compressed)
2690 conn->zlib_state = tor_zlib_new(0, ZLIB_METHOD);
2692 /* Prime the connection with some data. */
2693 conn->dir_spool_src = DIR_SPOOL_NETWORKSTATUS;
2694 connection_dirserv_flushed_some(conn);
2695 goto done;
2698 if (!strcmpstart(url,"/tor/status-vote/current/") ||
2699 !strcmpstart(url,"/tor/status-vote/next/")) {
2700 /* XXXX If-modified-since is only implemented for the current
2701 * consensus: that's probably fine, since it's the only vote document
2702 * people fetch much. */
2703 int current;
2704 ssize_t body_len = 0;
2705 ssize_t estimated_len = 0;
2706 smartlist_t *items = smartlist_create();
2707 smartlist_t *dir_items = smartlist_create();
2708 int lifetime = 60; /* XXXX022 should actually use vote intervals. */
2709 url += strlen("/tor/status-vote/");
2710 current = !strcmpstart(url, "current/");
2711 url = strchr(url, '/');
2712 tor_assert(url);
2713 ++url;
2714 if (!strcmp(url, "consensus")) {
2715 const char *item;
2716 tor_assert(!current); /* we handle current consensus specially above,
2717 * since it wants to be spooled. */
2718 if ((item = dirvote_get_pending_consensus(FLAV_NS)))
2719 smartlist_add(items, (char*)item);
2720 } else if (!current && !strcmp(url, "consensus-signatures")) {
2721 /* XXXX the spec says that we should implement
2722 * current/consensus-signatures too. It doesn't seem to be needed,
2723 * though. */
2724 const char *item;
2725 if ((item=dirvote_get_pending_detached_signatures()))
2726 smartlist_add(items, (char*)item);
2727 } else if (!strcmp(url, "authority")) {
2728 const cached_dir_t *d;
2729 int flags = DGV_BY_ID |
2730 (current ? DGV_INCLUDE_PREVIOUS : DGV_INCLUDE_PENDING);
2731 if ((d=dirvote_get_vote(NULL, flags)))
2732 smartlist_add(dir_items, (cached_dir_t*)d);
2733 } else {
2734 const cached_dir_t *d;
2735 smartlist_t *fps = smartlist_create();
2736 int flags;
2737 if (!strcmpstart(url, "d/")) {
2738 url += 2;
2739 flags = DGV_INCLUDE_PENDING | DGV_INCLUDE_PREVIOUS;
2740 } else {
2741 flags = DGV_BY_ID |
2742 (current ? DGV_INCLUDE_PREVIOUS : DGV_INCLUDE_PENDING);
2744 dir_split_resource_into_fingerprints(url, fps, NULL,
2745 DSR_HEX|DSR_SORT_UNIQ);
2746 SMARTLIST_FOREACH(fps, char *, fp, {
2747 if ((d = dirvote_get_vote(fp, flags)))
2748 smartlist_add(dir_items, (cached_dir_t*)d);
2749 tor_free(fp);
2751 smartlist_free(fps);
2753 if (!smartlist_len(dir_items) && !smartlist_len(items)) {
2754 write_http_status_line(conn, 404, "Not found");
2755 goto vote_done;
2757 SMARTLIST_FOREACH(dir_items, cached_dir_t *, d,
2758 body_len += compressed ? d->dir_z_len : d->dir_len);
2759 estimated_len += body_len;
2760 SMARTLIST_FOREACH(items, const char *, item, {
2761 size_t ln = strlen(item);
2762 if (compressed) {
2763 estimated_len += ln/2;
2764 } else {
2765 body_len += ln; estimated_len += ln;
2769 if (global_write_bucket_low(TO_CONN(conn), estimated_len, 2)) {
2770 write_http_status_line(conn, 503, "Directory busy, try again later.");
2771 goto vote_done;
2773 write_http_response_header(conn, body_len ? body_len : -1, compressed,
2774 lifetime);
2776 if (smartlist_len(items)) {
2777 if (compressed) {
2778 conn->zlib_state = tor_zlib_new(1, ZLIB_METHOD);
2779 SMARTLIST_FOREACH(items, const char *, c,
2780 connection_write_to_buf_zlib(c, strlen(c), conn, 0));
2781 connection_write_to_buf_zlib("", 0, conn, 1);
2782 } else {
2783 SMARTLIST_FOREACH(items, const char *, c,
2784 connection_write_to_buf(c, strlen(c), TO_CONN(conn)));
2786 } else {
2787 SMARTLIST_FOREACH(dir_items, cached_dir_t *, d,
2788 connection_write_to_buf(compressed ? d->dir_z : d->dir,
2789 compressed ? d->dir_z_len : d->dir_len,
2790 TO_CONN(conn)));
2792 vote_done:
2793 smartlist_free(items);
2794 smartlist_free(dir_items);
2795 goto done;
2798 if (!strcmpstart(url, "/tor/micro/d/")) {
2799 smartlist_t *fps = smartlist_create();
2801 dir_split_resource_into_fingerprints(url+strlen("/tor/micro/d/"),
2802 fps, NULL,
2803 DSR_DIGEST256|DSR_BASE64|DSR_SORT_UNIQ);
2805 if (!dirserv_have_any_microdesc(fps)) {
2806 write_http_status_line(conn, 404, "Not found");
2807 SMARTLIST_FOREACH(fps, char *, fp, tor_free(fp));
2808 smartlist_free(fps);
2809 goto done;
2811 dlen = dirserv_estimate_microdesc_size(fps, compressed);
2812 if (global_write_bucket_low(TO_CONN(conn), dlen, 2)) {
2813 log_info(LD_DIRSERV,
2814 "Client asked for server descriptors, but we've been "
2815 "writing too many bytes lately. Sending 503 Dir busy.");
2816 write_http_status_line(conn, 503, "Directory busy, try again later");
2817 SMARTLIST_FOREACH(fps, char *, fp, tor_free(fp));
2818 smartlist_free(fps);
2819 goto done;
2822 write_http_response_header(conn, -1, compressed, MICRODESC_CACHE_LIFETIME);
2823 conn->dir_spool_src = DIR_SPOOL_MICRODESC;
2824 conn->fingerprint_stack = fps;
2826 if (compressed)
2827 conn->zlib_state = tor_zlib_new(1, ZLIB_METHOD);
2829 connection_dirserv_flushed_some(conn);
2830 goto done;
2833 if (!strcmpstart(url,"/tor/server/") ||
2834 (!options->BridgeAuthoritativeDir &&
2835 !options->BridgeRelay && !strcmpstart(url,"/tor/extra/"))) {
2836 int res;
2837 const char *msg;
2838 const char *request_type = NULL;
2839 int cache_lifetime = 0;
2840 int is_extra = !strcmpstart(url,"/tor/extra/");
2841 url += is_extra ? strlen("/tor/extra/") : strlen("/tor/server/");
2842 conn->fingerprint_stack = smartlist_create();
2843 res = dirserv_get_routerdesc_fingerprints(conn->fingerprint_stack, url,
2844 &msg,
2845 !connection_dir_is_encrypted(conn),
2846 is_extra);
2848 if (!strcmpstart(url, "fp/")) {
2849 request_type = compressed?"/tor/server/fp.z":"/tor/server/fp";
2850 if (smartlist_len(conn->fingerprint_stack) == 1)
2851 cache_lifetime = ROUTERDESC_CACHE_LIFETIME;
2852 } else if (!strcmpstart(url, "authority")) {
2853 request_type = compressed?"/tor/server/authority.z":
2854 "/tor/server/authority";
2855 cache_lifetime = ROUTERDESC_CACHE_LIFETIME;
2856 } else if (!strcmpstart(url, "all")) {
2857 request_type = compressed?"/tor/server/all.z":"/tor/server/all";
2858 cache_lifetime = FULL_DIR_CACHE_LIFETIME;
2859 } else if (!strcmpstart(url, "d/")) {
2860 request_type = compressed?"/tor/server/d.z":"/tor/server/d";
2861 if (smartlist_len(conn->fingerprint_stack) == 1)
2862 cache_lifetime = ROUTERDESC_BY_DIGEST_CACHE_LIFETIME;
2863 } else {
2864 request_type = "/tor/server/?";
2866 (void) request_type; /* usable for note_request. */
2867 if (!strcmpstart(url, "d/"))
2868 conn->dir_spool_src =
2869 is_extra ? DIR_SPOOL_EXTRA_BY_DIGEST : DIR_SPOOL_SERVER_BY_DIGEST;
2870 else
2871 conn->dir_spool_src =
2872 is_extra ? DIR_SPOOL_EXTRA_BY_FP : DIR_SPOOL_SERVER_BY_FP;
2874 if (!dirserv_have_any_serverdesc(conn->fingerprint_stack,
2875 conn->dir_spool_src)) {
2876 res = -1;
2877 msg = "Not found";
2880 if (res < 0)
2881 write_http_status_line(conn, 404, msg);
2882 else {
2883 dlen = dirserv_estimate_data_size(conn->fingerprint_stack,
2884 1, compressed);
2885 if (global_write_bucket_low(TO_CONN(conn), dlen, 2)) {
2886 log_info(LD_DIRSERV,
2887 "Client asked for server descriptors, but we've been "
2888 "writing too many bytes lately. Sending 503 Dir busy.");
2889 write_http_status_line(conn, 503, "Directory busy, try again later");
2890 conn->dir_spool_src = DIR_SPOOL_NONE;
2891 goto done;
2893 write_http_response_header(conn, -1, compressed, cache_lifetime);
2894 if (compressed)
2895 conn->zlib_state = tor_zlib_new(1, ZLIB_METHOD);
2896 /* Prime the connection with some data. */
2897 connection_dirserv_flushed_some(conn);
2899 goto done;
2902 if (!strcmpstart(url,"/tor/keys/")) {
2903 smartlist_t *certs = smartlist_create();
2904 ssize_t len = -1;
2905 if (!strcmp(url, "/tor/keys/all")) {
2906 authority_cert_get_all(certs);
2907 } else if (!strcmp(url, "/tor/keys/authority")) {
2908 authority_cert_t *cert = get_my_v3_authority_cert();
2909 if (cert)
2910 smartlist_add(certs, cert);
2911 } else if (!strcmpstart(url, "/tor/keys/fp/")) {
2912 smartlist_t *fps = smartlist_create();
2913 dir_split_resource_into_fingerprints(url+strlen("/tor/keys/fp/"),
2914 fps, NULL,
2915 DSR_HEX|DSR_SORT_UNIQ);
2916 SMARTLIST_FOREACH(fps, char *, d, {
2917 authority_cert_t *c = authority_cert_get_newest_by_id(d);
2918 if (c) smartlist_add(certs, c);
2919 tor_free(d);
2921 smartlist_free(fps);
2922 } else if (!strcmpstart(url, "/tor/keys/sk/")) {
2923 smartlist_t *fps = smartlist_create();
2924 dir_split_resource_into_fingerprints(url+strlen("/tor/keys/sk/"),
2925 fps, NULL,
2926 DSR_HEX|DSR_SORT_UNIQ);
2927 SMARTLIST_FOREACH(fps, char *, d, {
2928 authority_cert_t *c = authority_cert_get_by_sk_digest(d);
2929 if (c) smartlist_add(certs, c);
2930 tor_free(d);
2932 smartlist_free(fps);
2933 } else if (!strcmpstart(url, "/tor/keys/fp-sk/")) {
2934 smartlist_t *fp_sks = smartlist_create();
2935 dir_split_resource_into_fingerprint_pairs(url+strlen("/tor/keys/fp-sk/"),
2936 fp_sks);
2937 SMARTLIST_FOREACH(fp_sks, fp_pair_t *, pair, {
2938 authority_cert_t *c = authority_cert_get_by_digests(pair->first,
2939 pair->second);
2940 if (c) smartlist_add(certs, c);
2941 tor_free(pair);
2943 smartlist_free(fp_sks);
2944 } else {
2945 write_http_status_line(conn, 400, "Bad request");
2946 goto keys_done;
2948 if (!smartlist_len(certs)) {
2949 write_http_status_line(conn, 404, "Not found");
2950 goto keys_done;
2952 SMARTLIST_FOREACH(certs, authority_cert_t *, c,
2953 if (c->cache_info.published_on < if_modified_since)
2954 SMARTLIST_DEL_CURRENT(certs, c));
2955 if (!smartlist_len(certs)) {
2956 write_http_status_line(conn, 304, "Not modified");
2957 goto keys_done;
2959 len = 0;
2960 SMARTLIST_FOREACH(certs, authority_cert_t *, c,
2961 len += c->cache_info.signed_descriptor_len);
2963 if (global_write_bucket_low(TO_CONN(conn), compressed?len/2:len, 2)) {
2964 write_http_status_line(conn, 503, "Directory busy, try again later.");
2965 goto keys_done;
2968 write_http_response_header(conn, compressed?-1:len, compressed, 60*60);
2969 if (compressed) {
2970 conn->zlib_state = tor_zlib_new(1, ZLIB_METHOD);
2971 SMARTLIST_FOREACH(certs, authority_cert_t *, c,
2972 connection_write_to_buf_zlib(c->cache_info.signed_descriptor_body,
2973 c->cache_info.signed_descriptor_len,
2974 conn, 0));
2975 connection_write_to_buf_zlib("", 0, conn, 1);
2976 } else {
2977 SMARTLIST_FOREACH(certs, authority_cert_t *, c,
2978 connection_write_to_buf(c->cache_info.signed_descriptor_body,
2979 c->cache_info.signed_descriptor_len,
2980 TO_CONN(conn)));
2982 keys_done:
2983 smartlist_free(certs);
2984 goto done;
2987 if (options->HidServDirectoryV2 &&
2988 !strcmpstart(url,"/tor/rendezvous2/")) {
2989 /* Handle v2 rendezvous descriptor fetch request. */
2990 const char *descp;
2991 const char *query = url + strlen("/tor/rendezvous2/");
2992 if (strlen(query) == REND_DESC_ID_V2_LEN_BASE32) {
2993 log_info(LD_REND, "Got a v2 rendezvous descriptor request for ID '%s'",
2994 safe_str(query));
2995 switch (rend_cache_lookup_v2_desc_as_dir(query, &descp)) {
2996 case 1: /* valid */
2997 write_http_response_header(conn, strlen(descp), 0, 0);
2998 connection_write_to_buf(descp, strlen(descp), TO_CONN(conn));
2999 break;
3000 case 0: /* well-formed but not present */
3001 write_http_status_line(conn, 404, "Not found");
3002 break;
3003 case -1: /* not well-formed */
3004 write_http_status_line(conn, 400, "Bad request");
3005 break;
3007 } else { /* not well-formed */
3008 write_http_status_line(conn, 400, "Bad request");
3010 goto done;
3013 if (options->HSAuthoritativeDir && !strcmpstart(url,"/tor/rendezvous/")) {
3014 /* rendezvous descriptor fetch */
3015 const char *descp;
3016 size_t desc_len;
3017 const char *query = url+strlen("/tor/rendezvous/");
3019 log_info(LD_REND, "Handling rendezvous descriptor get");
3020 switch (rend_cache_lookup_desc(query, 0, &descp, &desc_len)) {
3021 case 1: /* valid */
3022 write_http_response_header_impl(conn, desc_len,
3023 "application/octet-stream",
3024 NULL, NULL, 0);
3025 note_request("/tor/rendezvous?/", desc_len);
3026 /* need to send descp separately, because it may include NULs */
3027 connection_write_to_buf(descp, desc_len, TO_CONN(conn));
3028 break;
3029 case 0: /* well-formed but not present */
3030 write_http_status_line(conn, 404, "Not found");
3031 break;
3032 case -1: /* not well-formed */
3033 write_http_status_line(conn, 400, "Bad request");
3034 break;
3036 goto done;
3039 if (options->BridgeAuthoritativeDir &&
3040 options->BridgePassword &&
3041 connection_dir_is_encrypted(conn) &&
3042 !strcmp(url,"/tor/networkstatus-bridges")) {
3043 char *status;
3044 char *secret = alloc_http_authenticator(options->BridgePassword);
3046 header = http_get_header(headers, "Authorization: Basic ");
3048 /* now make sure the password is there and right */
3049 if (!header || strcmp(header, secret)) {
3050 write_http_status_line(conn, 404, "Not found");
3051 tor_free(secret);
3052 tor_free(header);
3053 goto done;
3055 tor_free(secret);
3056 tor_free(header);
3058 /* all happy now. send an answer. */
3059 status = networkstatus_getinfo_by_purpose("bridge", time(NULL));
3060 dlen = strlen(status);
3061 write_http_response_header(conn, dlen, 0, 0);
3062 connection_write_to_buf(status, dlen, TO_CONN(conn));
3063 tor_free(status);
3064 goto done;
3067 if (!strcmpstart(url,"/tor/bytes.txt")) {
3068 char *bytes = directory_dump_request_log();
3069 size_t len = strlen(bytes);
3070 write_http_response_header(conn, len, 0, 0);
3071 connection_write_to_buf(bytes, len, TO_CONN(conn));
3072 tor_free(bytes);
3073 goto done;
3076 if (!strcmp(url,"/tor/robots.txt")) { /* /robots.txt will have been
3077 rewritten to /tor/robots.txt */
3078 char robots[] = "User-agent: *\r\nDisallow: /\r\n";
3079 size_t len = strlen(robots);
3080 write_http_response_header(conn, len, 0, ROBOTS_CACHE_LIFETIME);
3081 connection_write_to_buf(robots, len, TO_CONN(conn));
3082 goto done;
3085 if (!strcmp(url,"/tor/dbg-stability.txt")) {
3086 const char *stability;
3087 size_t len;
3088 if (options->BridgeAuthoritativeDir ||
3089 ! authdir_mode_tests_reachability(options) ||
3090 ! (stability = rep_hist_get_router_stability_doc(time(NULL)))) {
3091 write_http_status_line(conn, 404, "Not found.");
3092 goto done;
3095 len = strlen(stability);
3096 write_http_response_header(conn, len, 0, 0);
3097 connection_write_to_buf(stability, len, TO_CONN(conn));
3098 goto done;
3101 #if defined(EXPORTMALLINFO) && defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO)
3102 #define ADD_MALLINFO_LINE(x) do { \
3103 tor_snprintf(tmp, sizeof(tmp), "%s %d\n", #x, mi.x); \
3104 smartlist_add(lines, tor_strdup(tmp)); \
3105 }while(0);
3107 if (!strcmp(url,"/tor/mallinfo.txt") &&
3108 (tor_addr_eq_ipv4h(&conn->_base.addr, 0x7f000001ul))) {
3109 char *result;
3110 size_t len;
3111 struct mallinfo mi;
3112 smartlist_t *lines;
3113 char tmp[256];
3115 memset(&mi, 0, sizeof(mi));
3116 mi = mallinfo();
3117 lines = smartlist_create();
3119 ADD_MALLINFO_LINE(arena)
3120 ADD_MALLINFO_LINE(ordblks)
3121 ADD_MALLINFO_LINE(smblks)
3122 ADD_MALLINFO_LINE(hblks)
3123 ADD_MALLINFO_LINE(hblkhd)
3124 ADD_MALLINFO_LINE(usmblks)
3125 ADD_MALLINFO_LINE(fsmblks)
3126 ADD_MALLINFO_LINE(uordblks)
3127 ADD_MALLINFO_LINE(fordblks)
3128 ADD_MALLINFO_LINE(keepcost)
3130 result = smartlist_join_strings(lines, "", 0, NULL);
3131 SMARTLIST_FOREACH(lines, char *, cp, tor_free(cp));
3132 smartlist_free(lines);
3134 len = strlen(result);
3135 write_http_response_header(conn, len, 0, 0);
3136 connection_write_to_buf(result, len, TO_CONN(conn));
3137 tor_free(result);
3138 goto done;
3140 #endif
3142 /* we didn't recognize the url */
3143 write_http_status_line(conn, 404, "Not found");
3145 done:
3146 tor_free(url_mem);
3147 return 0;
3150 /** Helper function: called when a dirserver gets a complete HTTP POST
3151 * request. Look for an uploaded server descriptor or rendezvous
3152 * service descriptor. On finding one, process it and write a
3153 * response into conn-\>outbuf. If the request is unrecognized, send a
3154 * 400. Always return 0. */
3155 static int
3156 directory_handle_command_post(dir_connection_t *conn, const char *headers,
3157 const char *body, size_t body_len)
3159 char *url = NULL;
3160 or_options_t *options = get_options();
3162 log_debug(LD_DIRSERV,"Received POST command.");
3164 conn->_base.state = DIR_CONN_STATE_SERVER_WRITING;
3166 if (parse_http_url(headers, &url) < 0) {
3167 write_http_status_line(conn, 400, "Bad request");
3168 return 0;
3170 log_debug(LD_DIRSERV,"rewritten url as '%s'.", url);
3172 /* Handle v2 rendezvous service publish request. */
3173 if (options->HidServDirectoryV2 &&
3174 !strcmpstart(url,"/tor/rendezvous2/publish")) {
3175 switch (rend_cache_store_v2_desc_as_dir(body)) {
3176 case -2:
3177 log_info(LD_REND, "Rejected v2 rend descriptor (length %d) from %s "
3178 "since we're not currently a hidden service directory.",
3179 (int)body_len, conn->_base.address);
3180 write_http_status_line(conn, 503, "Currently not acting as v2 "
3181 "hidden service directory");
3182 break;
3183 case -1:
3184 log_warn(LD_REND, "Rejected v2 rend descriptor (length %d) from %s.",
3185 (int)body_len, conn->_base.address);
3186 write_http_status_line(conn, 400,
3187 "Invalid v2 service descriptor rejected");
3188 break;
3189 default:
3190 write_http_status_line(conn, 200, "Service descriptor (v2) stored");
3191 log_info(LD_REND, "Handled v2 rendezvous descriptor post: accepted");
3193 goto done;
3196 if (!authdir_mode(options)) {
3197 /* we just provide cached directories; we don't want to
3198 * receive anything. */
3199 write_http_status_line(conn, 400, "Nonauthoritative directory does not "
3200 "accept posted server descriptors");
3201 goto done;
3204 if (authdir_mode_handles_descs(options, -1) &&
3205 !strcmp(url,"/tor/")) { /* server descriptor post */
3206 const char *msg = "[None]";
3207 uint8_t purpose = authdir_mode_bridge(options) ?
3208 ROUTER_PURPOSE_BRIDGE : ROUTER_PURPOSE_GENERAL;
3209 was_router_added_t r = dirserv_add_multiple_descriptors(body, purpose,
3210 conn->_base.address, &msg);
3211 tor_assert(msg);
3212 if (WRA_WAS_ADDED(r))
3213 dirserv_get_directory(); /* rebuild and write to disk */
3215 if (r == ROUTER_ADDED_NOTIFY_GENERATOR) {
3216 /* Accepted with a message. */
3217 log_info(LD_DIRSERV,
3218 "Problematic router descriptor or extra-info from %s "
3219 "(\"%s\").",
3220 conn->_base.address, msg);
3221 write_http_status_line(conn, 400, msg);
3222 } else if (r == ROUTER_ADDED_SUCCESSFULLY) {
3223 write_http_status_line(conn, 200, msg);
3224 } else if (WRA_WAS_OUTDATED(r)) {
3225 write_http_response_header_impl(conn, -1, NULL, NULL,
3226 "X-Descriptor-Not-New: Yes\r\n", -1);
3227 } else {
3228 log_info(LD_DIRSERV,
3229 "Rejected router descriptor or extra-info from %s "
3230 "(\"%s\").",
3231 conn->_base.address, msg);
3232 write_http_status_line(conn, 400, msg);
3234 goto done;
3237 if (options->HSAuthoritativeDir &&
3238 !strcmpstart(url,"/tor/rendezvous/publish")) {
3239 /* rendezvous descriptor post */
3240 log_info(LD_REND, "Handling rendezvous descriptor post.");
3241 if (rend_cache_store(body, body_len, 1) < 0) {
3242 log_fn(LOG_PROTOCOL_WARN, LD_DIRSERV,
3243 "Rejected rend descriptor (length %d) from %s.",
3244 (int)body_len, conn->_base.address);
3245 write_http_status_line(conn, 400,
3246 "Invalid v0 service descriptor rejected");
3247 } else {
3248 write_http_status_line(conn, 200, "Service descriptor (v0) stored");
3250 goto done;
3253 if (authdir_mode_v3(options) &&
3254 !strcmp(url,"/tor/post/vote")) { /* v3 networkstatus vote */
3255 const char *msg = "OK";
3256 int status;
3257 if (dirvote_add_vote(body, &msg, &status)) {
3258 write_http_status_line(conn, status, "Vote stored");
3259 } else {
3260 tor_assert(msg);
3261 write_http_status_line(conn, status, msg);
3263 goto done;
3266 if (authdir_mode_v3(options) &&
3267 !strcmp(url,"/tor/post/consensus-signature")) { /* sigs on consensus. */
3268 const char *msg = NULL;
3269 if (dirvote_add_signatures(body, conn->_base.address, &msg)>=0) {
3270 write_http_status_line(conn, 200, msg?msg:"Signatures stored");
3271 } else {
3272 log_warn(LD_DIR, "Unable to store signatures posted by %s: %s",
3273 conn->_base.address, msg?msg:"???");
3274 write_http_status_line(conn, 400, msg?msg:"Unable to store signatures");
3276 goto done;
3279 /* we didn't recognize the url */
3280 write_http_status_line(conn, 404, "Not found");
3282 done:
3283 tor_free(url);
3284 return 0;
3287 /** Called when a dirserver receives data on a directory connection;
3288 * looks for an HTTP request. If the request is complete, remove it
3289 * from the inbuf, try to process it; otherwise, leave it on the
3290 * buffer. Return a 0 on success, or -1 on error.
3292 static int
3293 directory_handle_command(dir_connection_t *conn)
3295 char *headers=NULL, *body=NULL;
3296 size_t body_len=0;
3297 int r;
3299 tor_assert(conn);
3300 tor_assert(conn->_base.type == CONN_TYPE_DIR);
3302 switch (fetch_from_buf_http(conn->_base.inbuf,
3303 &headers, MAX_HEADERS_SIZE,
3304 &body, &body_len, MAX_DIR_UL_SIZE, 0)) {
3305 case -1: /* overflow */
3306 log_warn(LD_DIRSERV,
3307 "Request too large from address '%s' to DirPort. Closing.",
3308 safe_str(conn->_base.address));
3309 return -1;
3310 case 0:
3311 log_debug(LD_DIRSERV,"command not all here yet.");
3312 return 0;
3313 /* case 1, fall through */
3316 http_set_address_origin(headers, TO_CONN(conn));
3317 //log_debug(LD_DIRSERV,"headers %s, body %s.", headers, body);
3319 if (!strncasecmp(headers,"GET",3))
3320 r = directory_handle_command_get(conn, headers, body, body_len);
3321 else if (!strncasecmp(headers,"POST",4))
3322 r = directory_handle_command_post(conn, headers, body, body_len);
3323 else {
3324 log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
3325 "Got headers %s with unknown command. Closing.",
3326 escaped(headers));
3327 r = -1;
3330 tor_free(headers); tor_free(body);
3331 return r;
3334 /** Write handler for directory connections; called when all data has
3335 * been flushed. Close the connection or wait for a response as
3336 * appropriate.
3339 connection_dir_finished_flushing(dir_connection_t *conn)
3341 tor_assert(conn);
3342 tor_assert(conn->_base.type == CONN_TYPE_DIR);
3344 /* Note that we have finished writing the directory response. For direct
3345 * connections this means we're done, for tunneled connections its only
3346 * an intermediate step. */
3347 if (TO_CONN(conn)->dirreq_id)
3348 geoip_change_dirreq_state(TO_CONN(conn)->dirreq_id, DIRREQ_TUNNELED,
3349 DIRREQ_FLUSHING_DIR_CONN_FINISHED);
3350 else
3351 geoip_change_dirreq_state(TO_CONN(conn)->global_identifier,
3352 DIRREQ_DIRECT,
3353 DIRREQ_FLUSHING_DIR_CONN_FINISHED);
3354 switch (conn->_base.state) {
3355 case DIR_CONN_STATE_CLIENT_SENDING:
3356 log_debug(LD_DIR,"client finished sending command.");
3357 conn->_base.state = DIR_CONN_STATE_CLIENT_READING;
3358 connection_stop_writing(TO_CONN(conn));
3359 return 0;
3360 case DIR_CONN_STATE_SERVER_WRITING:
3361 log_debug(LD_DIRSERV,"Finished writing server response. Closing.");
3362 connection_mark_for_close(TO_CONN(conn));
3363 return 0;
3364 default:
3365 log_warn(LD_BUG,"called in unexpected state %d.",
3366 conn->_base.state);
3367 tor_fragile_assert();
3368 return -1;
3370 return 0;
3373 /** Connected handler for directory connections: begin sending data to the
3374 * server */
3376 connection_dir_finished_connecting(dir_connection_t *conn)
3378 tor_assert(conn);
3379 tor_assert(conn->_base.type == CONN_TYPE_DIR);
3380 tor_assert(conn->_base.state == DIR_CONN_STATE_CONNECTING);
3382 log_debug(LD_HTTP,"Dir connection to router %s:%u established.",
3383 conn->_base.address,conn->_base.port);
3385 conn->_base.state = DIR_CONN_STATE_CLIENT_SENDING; /* start flushing conn */
3386 return 0;
3389 /** Called when one or more networkstatus fetches have failed (with uppercase
3390 * fingerprints listed in <b>failed</b>). Mark those fingerprints as having
3391 * failed once, unless they failed with status code 503. */
3392 static void
3393 dir_networkstatus_download_failed(smartlist_t *failed, int status_code)
3395 if (status_code == 503)
3396 return;
3397 SMARTLIST_FOREACH(failed, const char *, fp,
3399 char digest[DIGEST_LEN];
3400 trusted_dir_server_t *dir;
3401 if (base16_decode(digest, DIGEST_LEN, fp, strlen(fp))<0) {
3402 log_warn(LD_BUG, "Called with bad fingerprint in list: %s",
3403 escaped(fp));
3404 continue;
3406 dir = router_get_trusteddirserver_by_digest(digest);
3408 if (dir)
3409 download_status_failed(&dir->v2_ns_dl_status, status_code);
3413 /** Schedule for when servers should download things in general. */
3414 static const int server_dl_schedule[] = {
3415 0, 0, 0, 60, 60, 60*2, 60*5, 60*15, INT_MAX
3417 /** Schedule for when clients should download things in general. */
3418 static const int client_dl_schedule[] = {
3419 0, 0, 60, 60*5, 60*10, INT_MAX
3421 /** Schedule for when servers should download consensuses. */
3422 static const int server_consensus_dl_schedule[] = {
3423 0, 0, 60, 60*5, 60*10, 60*30, 60*30, 60*30, 60*30, 60*30, 60*60, 60*60*2
3425 /** Schedule for when clients should download consensuses. */
3426 static const int client_consensus_dl_schedule[] = {
3427 0, 0, 60, 60*5, 60*10, 60*30, 60*60, 60*60, 60*60, 60*60*3, 60*60*6, 60*60*12
3429 /** Schedule for when clients should download bridge descriptors. */
3430 static const int bridge_dl_schedule[] = {
3431 60*60, 15*60, 15*60, 60*60
3434 /** Decide which download schedule we want to use, and then return a
3435 * pointer to it along with a pointer to its length. Helper function for
3436 * download_status_increment_failure() and download_status_reset(). */
3437 static void
3438 find_dl_schedule_and_len(download_status_t *dls, int server,
3439 const int **schedule, size_t *schedule_len)
3441 switch (dls->schedule) {
3442 case DL_SCHED_GENERIC:
3443 if (server) {
3444 *schedule = server_dl_schedule;
3445 *schedule_len = sizeof(server_dl_schedule)/sizeof(int);
3446 } else {
3447 *schedule = client_dl_schedule;
3448 *schedule_len = sizeof(client_dl_schedule)/sizeof(int);
3450 break;
3451 case DL_SCHED_CONSENSUS:
3452 if (server) {
3453 *schedule = server_consensus_dl_schedule;
3454 *schedule_len = sizeof(server_consensus_dl_schedule)/sizeof(int);
3455 } else {
3456 *schedule = client_consensus_dl_schedule;
3457 *schedule_len = sizeof(client_consensus_dl_schedule)/sizeof(int);
3459 break;
3460 case DL_SCHED_BRIDGE:
3461 *schedule = bridge_dl_schedule;
3462 *schedule_len = sizeof(bridge_dl_schedule)/sizeof(int);
3463 break;
3464 default:
3465 tor_assert(0);
3469 /** Called when an attempt to download <b>dls</b> has failed with HTTP status
3470 * <b>status_code</b>. Increment the failure count (if the code indicates a
3471 * real failure) and set <b>dls</b>-\>next_attempt_at to an appropriate time
3472 * in the future. */
3473 time_t
3474 download_status_increment_failure(download_status_t *dls, int status_code,
3475 const char *item, int server, time_t now)
3477 const int *schedule;
3478 size_t schedule_len;
3479 int increment;
3480 tor_assert(dls);
3481 if (status_code != 503 || server) {
3482 if (dls->n_download_failures < IMPOSSIBLE_TO_DOWNLOAD-1)
3483 ++dls->n_download_failures;
3486 find_dl_schedule_and_len(dls, server, &schedule, &schedule_len);
3488 if (dls->n_download_failures < schedule_len)
3489 increment = schedule[dls->n_download_failures];
3490 else if (dls->n_download_failures == IMPOSSIBLE_TO_DOWNLOAD)
3491 increment = INT_MAX;
3492 else
3493 increment = schedule[schedule_len-1];
3495 if (increment < INT_MAX)
3496 dls->next_attempt_at = now+increment;
3497 else
3498 dls->next_attempt_at = TIME_MAX;
3500 if (item) {
3501 if (increment == 0)
3502 log_debug(LD_DIR, "%s failed %d time(s); I'll try again immediately.",
3503 item, (int)dls->n_download_failures);
3504 else if (dls->next_attempt_at < TIME_MAX)
3505 log_debug(LD_DIR, "%s failed %d time(s); I'll try again in %d seconds.",
3506 item, (int)dls->n_download_failures,
3507 (int)(dls->next_attempt_at-now));
3508 else
3509 log_debug(LD_DIR, "%s failed %d time(s); Giving up for a while.",
3510 item, (int)dls->n_download_failures);
3512 return dls->next_attempt_at;
3515 /** Reset <b>dls</b> so that it will be considered downloadable
3516 * immediately, and/or to show that we don't need it anymore.
3518 * (We find the zeroth element of the download schedule, and set
3519 * next_attempt_at to be the appropriate offset from 'now'. In most
3520 * cases this means setting it to 'now', so the item will be immediately
3521 * downloadable; in the case of bridge descriptors, the zeroth element
3522 * is an hour from now.) */
3523 void
3524 download_status_reset(download_status_t *dls)
3526 const int *schedule;
3527 size_t schedule_len;
3529 find_dl_schedule_and_len(dls, get_options()->DirPort,
3530 &schedule, &schedule_len);
3532 dls->n_download_failures = 0;
3533 dls->next_attempt_at = time(NULL) + schedule[0];
3536 /** Return the number of failures on <b>dls</b> since the last success (if
3537 * any). */
3539 download_status_get_n_failures(const download_status_t *dls)
3541 return dls->n_download_failures;
3544 /** Called when one or more routerdesc (or extrainfo, if <b>was_extrainfo</b>)
3545 * fetches have failed (with uppercase fingerprints listed in <b>failed</b>,
3546 * either as descriptor digests or as identity digests based on
3547 * <b>was_descriptor_digests</b>).
3549 static void
3550 dir_routerdesc_download_failed(smartlist_t *failed, int status_code,
3551 int router_purpose,
3552 int was_extrainfo, int was_descriptor_digests)
3554 char digest[DIGEST_LEN];
3555 time_t now = time(NULL);
3556 int server = directory_fetches_from_authorities(get_options());
3557 if (!was_descriptor_digests) {
3558 if (router_purpose == ROUTER_PURPOSE_BRIDGE) {
3559 tor_assert(!was_extrainfo);
3560 connection_dir_retry_bridges(failed);
3562 return; /* FFFF should implement for other-than-router-purpose someday */
3564 SMARTLIST_FOREACH(failed, const char *, cp,
3566 download_status_t *dls = NULL;
3567 if (base16_decode(digest, DIGEST_LEN, cp, strlen(cp)) < 0) {
3568 log_warn(LD_BUG, "Malformed fingerprint in list: %s", escaped(cp));
3569 continue;
3571 if (was_extrainfo) {
3572 signed_descriptor_t *sd =
3573 router_get_by_extrainfo_digest(digest);
3574 if (sd)
3575 dls = &sd->ei_dl_status;
3576 } else {
3577 dls = router_get_dl_status_by_descriptor_digest(digest);
3579 if (!dls || dls->n_download_failures >= MAX_ROUTERDESC_DOWNLOAD_FAILURES)
3580 continue;
3581 download_status_increment_failure(dls, status_code, cp, server, now);
3584 /* No need to relaunch descriptor downloads here: we already do it
3585 * every 10 or 60 seconds (FOO_DESCRIPTOR_RETRY_INTERVAL) in main.c. */
3588 /** Helper. Compare two fp_pair_t objects, and return -1, 0, or 1 as
3589 * appropriate. */
3590 static int
3591 _compare_pairs(const void **a, const void **b)
3593 const fp_pair_t *fp1 = *a, *fp2 = *b;
3594 int r;
3595 if ((r = memcmp(fp1->first, fp2->first, DIGEST_LEN)))
3596 return r;
3597 else
3598 return memcmp(fp1->second, fp2->second, DIGEST_LEN);
3601 /** Divide a string <b>res</b> of the form FP1-FP2+FP3-FP4...[.z], where each
3602 * FP is a hex-encoded fingerprint, into a sequence of distinct sorted
3603 * fp_pair_t. Skip malformed pairs. On success, return 0 and add those
3604 * fp_pair_t into <b>pairs_out</b>. On failure, return -1. */
3606 dir_split_resource_into_fingerprint_pairs(const char *res,
3607 smartlist_t *pairs_out)
3609 smartlist_t *pairs_tmp = smartlist_create();
3610 smartlist_t *pairs_result = smartlist_create();
3612 smartlist_split_string(pairs_tmp, res, "+", 0, 0);
3613 if (smartlist_len(pairs_tmp)) {
3614 char *last = smartlist_get(pairs_tmp,smartlist_len(pairs_tmp)-1);
3615 size_t last_len = strlen(last);
3616 if (last_len > 2 && !strcmp(last+last_len-2, ".z")) {
3617 last[last_len-2] = '\0';
3620 SMARTLIST_FOREACH_BEGIN(pairs_tmp, char *, cp) {
3621 if (strlen(cp) != HEX_DIGEST_LEN*2+1) {
3622 log_info(LD_DIR,
3623 "Skipping digest pair %s with non-standard length.", escaped(cp));
3624 } else if (cp[HEX_DIGEST_LEN] != '-') {
3625 log_info(LD_DIR,
3626 "Skipping digest pair %s with missing dash.", escaped(cp));
3627 } else {
3628 fp_pair_t pair;
3629 if (base16_decode(pair.first, DIGEST_LEN, cp, HEX_DIGEST_LEN)<0 ||
3630 base16_decode(pair.second,
3631 DIGEST_LEN, cp+HEX_DIGEST_LEN+1, HEX_DIGEST_LEN)<0) {
3632 log_info(LD_DIR, "Skipping non-decodable digest pair %s", escaped(cp));
3633 } else {
3634 smartlist_add(pairs_result, tor_memdup(&pair, sizeof(pair)));
3637 tor_free(cp);
3638 } SMARTLIST_FOREACH_END(cp);
3639 smartlist_free(pairs_tmp);
3641 /* Uniq-and-sort */
3642 smartlist_sort(pairs_result, _compare_pairs);
3643 smartlist_uniq(pairs_result, _compare_pairs, _tor_free);
3645 smartlist_add_all(pairs_out, pairs_result);
3646 smartlist_free(pairs_result);
3647 return 0;
3650 /** Given a directory <b>resource</b> request, containing zero
3651 * or more strings separated by plus signs, followed optionally by ".z", store
3652 * the strings, in order, into <b>fp_out</b>. If <b>compressed_out</b> is
3653 * non-NULL, set it to 1 if the resource ends in ".z", else set it to 0.
3655 * If (flags & DSR_HEX), then delete all elements that aren't hex digests, and
3656 * decode the rest. If (flags & DSR_BASE64), then use "-" rather than "+" as
3657 * a separator, delete all the elements that aren't base64-encoded digests,
3658 * and decode the rest. If (flags & DSR_DIGEST256), these digests should be
3659 * 256 bits long; else they should be 160.
3661 * If (flags & DSR_SORT_UNIQ), then sort the list and remove all duplicates.
3664 dir_split_resource_into_fingerprints(const char *resource,
3665 smartlist_t *fp_out, int *compressed_out,
3666 int flags)
3668 const int decode_hex = flags & DSR_HEX;
3669 const int decode_base64 = flags & DSR_BASE64;
3670 const int digests_are_256 = flags & DSR_DIGEST256;
3671 const int sort_uniq = flags & DSR_SORT_UNIQ;
3673 const int digest_len = digests_are_256 ? DIGEST256_LEN : DIGEST_LEN;
3674 const int hex_digest_len = digests_are_256 ?
3675 HEX_DIGEST256_LEN : HEX_DIGEST_LEN;
3676 const int base64_digest_len = digests_are_256 ?
3677 BASE64_DIGEST256_LEN : BASE64_DIGEST_LEN;
3678 smartlist_t *fp_tmp = smartlist_create();
3680 tor_assert(!(decode_hex && decode_base64));
3681 tor_assert(fp_out);
3683 smartlist_split_string(fp_tmp, resource, decode_base64?"-":"+", 0, 0);
3684 if (compressed_out)
3685 *compressed_out = 0;
3686 if (smartlist_len(fp_tmp)) {
3687 char *last = smartlist_get(fp_tmp,smartlist_len(fp_tmp)-1);
3688 size_t last_len = strlen(last);
3689 if (last_len > 2 && !strcmp(last+last_len-2, ".z")) {
3690 last[last_len-2] = '\0';
3691 if (compressed_out)
3692 *compressed_out = 1;
3695 if (decode_hex || decode_base64) {
3696 const size_t encoded_len = decode_hex ? hex_digest_len : base64_digest_len;
3697 int i;
3698 char *cp, *d = NULL;
3699 for (i = 0; i < smartlist_len(fp_tmp); ++i) {
3700 cp = smartlist_get(fp_tmp, i);
3701 if (strlen(cp) != encoded_len) {
3702 log_info(LD_DIR,
3703 "Skipping digest %s with non-standard length.", escaped(cp));
3704 smartlist_del_keeporder(fp_tmp, i--);
3705 goto again;
3707 d = tor_malloc_zero(digest_len);
3708 if (decode_hex ?
3709 (base16_decode(d, digest_len, cp, hex_digest_len)<0) :
3710 (base64_decode(d, digest_len, cp, base64_digest_len)<0)) {
3711 log_info(LD_DIR, "Skipping non-decodable digest %s", escaped(cp));
3712 smartlist_del_keeporder(fp_tmp, i--);
3713 goto again;
3715 smartlist_set(fp_tmp, i, d);
3716 d = NULL;
3717 again:
3718 tor_free(cp);
3719 tor_free(d);
3722 if (sort_uniq) {
3723 if (decode_hex || decode_base64) {
3724 if (digests_are_256) {
3725 smartlist_sort_digests256(fp_tmp);
3726 smartlist_uniq_digests256(fp_tmp);
3727 } else {
3728 smartlist_sort_digests(fp_tmp);
3729 smartlist_uniq_digests(fp_tmp);
3731 } else {
3732 smartlist_sort_strings(fp_tmp);
3733 smartlist_uniq_strings(fp_tmp);
3736 smartlist_add_all(fp_out, fp_tmp);
3737 smartlist_free(fp_tmp);
3738 return 0;