naked constants are bad
[tor/rransom.git] / src / or / directory.c
blob52e1c392cf684c3fd45c3f7d28ada2d0279245c5
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 #if defined(EXPORTMALLINFO) && defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO)
8 #ifndef OPENBSD
9 #include <malloc.h>
10 #endif
11 #endif
13 /**
14 * \file directory.c
15 * \brief Code to send and fetch directories and router
16 * descriptors via HTTP. Directories use dirserv.c to generate the
17 * results; clients use routers.c to parse them.
18 **/
20 /* In-points to directory.c:
22 * - directory_post_to_dirservers(), called from
23 * router_upload_dir_desc_to_dirservers() in router.c
24 * upload_service_descriptor() in rendservice.c
25 * - directory_get_from_dirserver(), called from
26 * rend_client_refetch_renddesc() in rendclient.c
27 * run_scheduled_events() in main.c
28 * do_hup() in main.c
29 * - connection_dir_process_inbuf(), called from
30 * connection_process_inbuf() in connection.c
31 * - connection_dir_finished_flushing(), called from
32 * connection_finished_flushing() in connection.c
33 * - connection_dir_finished_connecting(), called from
34 * connection_finished_connecting() in connection.c
36 static void directory_send_command(dir_connection_t *conn,
37 int purpose, int direct, const char *resource,
38 const char *payload, size_t payload_len,
39 int supports_conditional_consensus,
40 time_t if_modified_since);
41 static int directory_handle_command(dir_connection_t *conn);
42 static int body_is_plausible(const char *body, size_t body_len, int purpose);
43 static int purpose_needs_anonymity(uint8_t dir_purpose,
44 uint8_t router_purpose);
45 static char *http_get_header(const char *headers, const char *which);
46 static void http_set_address_origin(const char *headers, connection_t *conn);
47 static void connection_dir_download_networkstatus_failed(
48 dir_connection_t *conn, int status_code);
49 static void connection_dir_download_routerdesc_failed(dir_connection_t *conn);
50 static void connection_dir_download_cert_failed(
51 dir_connection_t *conn, int status_code);
52 static void dir_networkstatus_download_failed(smartlist_t *failed,
53 int status_code);
54 static void dir_routerdesc_download_failed(smartlist_t *failed,
55 int status_code,
56 int router_purpose,
57 int was_extrainfo,
58 int was_descriptor_digests);
59 static void note_client_request(int purpose, int compressed, size_t bytes);
60 static int client_likes_consensus(networkstatus_t *v, const char *want_url);
62 static void directory_initiate_command_rend(const char *address,
63 const tor_addr_t *addr,
64 uint16_t or_port,
65 uint16_t dir_port,
66 int supports_conditional_consensus,
67 int supports_begindir,
68 const char *digest,
69 uint8_t dir_purpose,
70 uint8_t router_purpose,
71 int anonymized_connection,
72 const char *resource,
73 const char *payload,
74 size_t payload_len,
75 time_t if_modified_since,
76 const rend_data_t *rend_query);
78 /********* START VARIABLES **********/
80 /** How far in the future do we allow a directory server to tell us it is
81 * before deciding that one of us has the wrong time? */
82 #define ALLOW_DIRECTORY_TIME_SKEW (30*60)
84 #define X_ADDRESS_HEADER "X-Your-Address-Is: "
86 /** HTTP cache control: how long do we tell proxies they can cache each
87 * kind of document we serve? */
88 #define FULL_DIR_CACHE_LIFETIME (60*60)
89 #define RUNNINGROUTERS_CACHE_LIFETIME (20*60)
90 #define DIRPORTFRONTPAGE_CACHE_LIFETIME (20*60)
91 #define NETWORKSTATUS_CACHE_LIFETIME (5*60)
92 #define ROUTERDESC_CACHE_LIFETIME (30*60)
93 #define ROUTERDESC_BY_DIGEST_CACHE_LIFETIME (48*60*60)
94 #define ROBOTS_CACHE_LIFETIME (24*60*60)
95 #define MICRODESC_CACHE_LIFETIME (48*60*60)
97 /********* END VARIABLES ************/
99 /** Return true iff the directory purpose <b>dir_purpose</b> (and if it's
100 * fetching descriptors, it's fetching them for <b>router_purpose</b>)
101 * must use an anonymous connection to a directory. */
102 static int
103 purpose_needs_anonymity(uint8_t dir_purpose, uint8_t router_purpose)
105 if (get_options()->AllDirActionsPrivate)
106 return 1;
107 if (router_purpose == ROUTER_PURPOSE_BRIDGE && has_completed_circuit)
108 return 1; /* if no circuits yet, we may need this info to bootstrap. */
109 if (dir_purpose == DIR_PURPOSE_UPLOAD_DIR ||
110 dir_purpose == DIR_PURPOSE_UPLOAD_VOTE ||
111 dir_purpose == DIR_PURPOSE_UPLOAD_SIGNATURES ||
112 dir_purpose == DIR_PURPOSE_FETCH_V2_NETWORKSTATUS ||
113 dir_purpose == DIR_PURPOSE_FETCH_STATUS_VOTE ||
114 dir_purpose == DIR_PURPOSE_FETCH_DETACHED_SIGNATURES ||
115 dir_purpose == DIR_PURPOSE_FETCH_CONSENSUS ||
116 dir_purpose == DIR_PURPOSE_FETCH_CERTIFICATE ||
117 dir_purpose == DIR_PURPOSE_FETCH_SERVERDESC ||
118 dir_purpose == DIR_PURPOSE_FETCH_EXTRAINFO)
119 return 0;
120 return 1;
123 /** Return a newly allocated string describing <b>auth</b>. */
124 char *
125 authority_type_to_string(authority_type_t auth)
127 char *result;
128 smartlist_t *lst = smartlist_create();
129 if (auth & V1_AUTHORITY)
130 smartlist_add(lst, (void*)"V1");
131 if (auth & V2_AUTHORITY)
132 smartlist_add(lst, (void*)"V2");
133 if (auth & V3_AUTHORITY)
134 smartlist_add(lst, (void*)"V3");
135 if (auth & BRIDGE_AUTHORITY)
136 smartlist_add(lst, (void*)"Bridge");
137 if (auth & HIDSERV_AUTHORITY)
138 smartlist_add(lst, (void*)"Hidden service");
139 if (smartlist_len(lst)) {
140 result = smartlist_join_strings(lst, ", ", 0, NULL);
141 } else {
142 result = tor_strdup("[Not an authority]");
144 smartlist_free(lst);
145 return result;
148 /** Return a string describing a given directory connection purpose. */
149 static const char *
150 dir_conn_purpose_to_string(int purpose)
152 switch (purpose)
154 case DIR_PURPOSE_FETCH_RENDDESC:
155 return "hidden-service descriptor fetch";
156 case DIR_PURPOSE_UPLOAD_DIR:
157 return "server descriptor upload";
158 case DIR_PURPOSE_UPLOAD_RENDDESC:
159 return "hidden-service descriptor upload";
160 case DIR_PURPOSE_UPLOAD_VOTE:
161 return "server vote upload";
162 case DIR_PURPOSE_UPLOAD_SIGNATURES:
163 return "consensus signature upload";
164 case DIR_PURPOSE_FETCH_V2_NETWORKSTATUS:
165 return "network-status fetch";
166 case DIR_PURPOSE_FETCH_SERVERDESC:
167 return "server descriptor fetch";
168 case DIR_PURPOSE_FETCH_EXTRAINFO:
169 return "extra-info fetch";
170 case DIR_PURPOSE_FETCH_CONSENSUS:
171 return "consensus network-status fetch";
172 case DIR_PURPOSE_FETCH_CERTIFICATE:
173 return "authority cert fetch";
174 case DIR_PURPOSE_FETCH_STATUS_VOTE:
175 return "status vote fetch";
176 case DIR_PURPOSE_FETCH_DETACHED_SIGNATURES:
177 return "consensus signature fetch";
178 case DIR_PURPOSE_FETCH_RENDDESC_V2:
179 return "hidden-service v2 descriptor fetch";
180 case DIR_PURPOSE_UPLOAD_RENDDESC_V2:
181 return "hidden-service v2 descriptor upload";
184 log_warn(LD_BUG, "Called with unknown purpose %d", purpose);
185 return "(unknown)";
188 /** Return true iff <b>identity_digest</b> is the digest of a router we
189 * believe to support extrainfo downloads. (If <b>is_authority</b> we do
190 * additional checking that's only valid for authorities.) */
192 router_supports_extrainfo(const char *identity_digest, int is_authority)
194 routerinfo_t *ri = router_get_by_digest(identity_digest);
196 if (ri) {
197 if (ri->caches_extra_info)
198 return 1;
199 if (is_authority && ri->platform &&
200 tor_version_as_new_as(ri->platform, "Tor 0.2.0.0-alpha-dev (r10070)"))
201 return 1;
203 if (is_authority) {
204 routerstatus_t *rs = router_get_consensus_status_by_id(identity_digest);
205 if (rs && rs->version_supports_extrainfo_upload)
206 return 1;
208 return 0;
211 /** Return true iff any trusted directory authority has accepted our
212 * server descriptor.
214 * We consider any authority sufficient because waiting for all of
215 * them means it never happens while any authority is down; we don't
216 * go for something more complex in the middle (like \>1/3 or \>1/2 or
217 * \>=1/2) because that doesn't seem necessary yet.
220 directories_have_accepted_server_descriptor(void)
222 smartlist_t *servers = router_get_trusted_dir_servers();
223 or_options_t *options = get_options();
224 SMARTLIST_FOREACH(servers, trusted_dir_server_t *, d, {
225 if ((d->type & options->_PublishServerDescriptor) &&
226 d->has_accepted_serverdesc) {
227 return 1;
230 return 0;
233 /** Start a connection to every suitable directory authority, using
234 * connection purpose 'purpose' and uploading the payload 'payload'
235 * (length 'payload_len'). dir_purpose should be one of
236 * 'DIR_PURPOSE_UPLOAD_DIR' or 'DIR_PURPOSE_UPLOAD_RENDDESC'.
238 * <b>type</b> specifies what sort of dir authorities (V1, V2,
239 * HIDSERV, BRIDGE) we should upload to.
241 * If <b>extrainfo_len</b> is nonzero, the first <b>payload_len</b> bytes of
242 * <b>payload</b> hold a router descriptor, and the next <b>extrainfo_len</b>
243 * bytes of <b>payload</b> hold an extra-info document. Upload the descriptor
244 * to all authorities, and the extra-info document to all authorities that
245 * support it.
247 void
248 directory_post_to_dirservers(uint8_t dir_purpose, uint8_t router_purpose,
249 authority_type_t type,
250 const char *payload,
251 size_t payload_len, size_t extrainfo_len)
253 int post_via_tor;
254 smartlist_t *dirservers = router_get_trusted_dir_servers();
255 int found = 0;
256 tor_assert(dirservers);
257 /* This tries dirservers which we believe to be down, but ultimately, that's
258 * harmless, and we may as well err on the side of getting things uploaded.
260 SMARTLIST_FOREACH_BEGIN(dirservers, trusted_dir_server_t *, ds) {
261 routerstatus_t *rs = &(ds->fake_status);
262 size_t upload_len = payload_len;
263 tor_addr_t ds_addr;
265 if ((type & ds->type) == 0)
266 continue;
268 found = 1; /* at least one authority of this type was listed */
269 if (dir_purpose == DIR_PURPOSE_UPLOAD_DIR)
270 ds->has_accepted_serverdesc = 0;
272 if (extrainfo_len && router_supports_extrainfo(ds->digest, 1)) {
273 upload_len += extrainfo_len;
274 log_info(LD_DIR, "Uploading an extrainfo too (length %d)",
275 (int) extrainfo_len);
277 tor_addr_from_ipv4h(&ds_addr, ds->addr);
278 post_via_tor = purpose_needs_anonymity(dir_purpose, router_purpose) ||
279 !fascist_firewall_allows_address_dir(&ds_addr, ds->dir_port);
280 directory_initiate_command_routerstatus(rs, dir_purpose,
281 router_purpose,
282 post_via_tor,
283 NULL, payload, upload_len, 0);
284 } SMARTLIST_FOREACH_END(ds);
285 if (!found) {
286 char *s = authority_type_to_string(type);
287 log_warn(LD_DIR, "Publishing server descriptor to directory authorities "
288 "of type '%s', but no authorities of that type listed!", s);
289 tor_free(s);
293 /** Start a connection to a random running directory server, using
294 * connection purpose <b>dir_purpose</b>, intending to fetch descriptors
295 * of purpose <b>router_purpose</b>, and requesting <b>resource</b>.
296 * Use <b>pds_flags</b> as arguments to router_pick_directory_server()
297 * or router_pick_trusteddirserver().
299 void
300 directory_get_from_dirserver(uint8_t dir_purpose, uint8_t router_purpose,
301 const char *resource, int pds_flags)
303 routerstatus_t *rs = NULL;
304 or_options_t *options = get_options();
305 int prefer_authority = directory_fetches_from_authorities(options);
306 int get_via_tor = purpose_needs_anonymity(dir_purpose, router_purpose);
307 authority_type_t type;
308 time_t if_modified_since = 0;
310 /* FFFF we could break this switch into its own function, and call
311 * it elsewhere in directory.c. -RD */
312 switch (dir_purpose) {
313 case DIR_PURPOSE_FETCH_EXTRAINFO:
314 type = EXTRAINFO_CACHE |
315 (router_purpose == ROUTER_PURPOSE_BRIDGE ? BRIDGE_AUTHORITY :
316 V3_AUTHORITY);
317 break;
318 case DIR_PURPOSE_FETCH_V2_NETWORKSTATUS:
319 type = V2_AUTHORITY;
320 break;
321 case DIR_PURPOSE_FETCH_SERVERDESC:
322 type = (router_purpose == ROUTER_PURPOSE_BRIDGE ? BRIDGE_AUTHORITY :
323 V3_AUTHORITY);
324 break;
325 case DIR_PURPOSE_FETCH_RENDDESC:
326 type = HIDSERV_AUTHORITY;
327 break;
328 case DIR_PURPOSE_FETCH_STATUS_VOTE:
329 case DIR_PURPOSE_FETCH_DETACHED_SIGNATURES:
330 type = V3_AUTHORITY;
331 break;
332 case DIR_PURPOSE_FETCH_CONSENSUS:
333 case DIR_PURPOSE_FETCH_CERTIFICATE:
334 type = V3_AUTHORITY;
335 break;
336 default:
337 log_warn(LD_BUG, "Unexpected purpose %d", (int)dir_purpose);
338 return;
341 if (dir_purpose == DIR_PURPOSE_FETCH_CONSENSUS) {
342 networkstatus_t *v = networkstatus_get_latest_consensus();
343 if (v)
344 if_modified_since = v->valid_after + 180;
347 if (!options->FetchServerDescriptors && type != HIDSERV_AUTHORITY)
348 return;
350 if (!get_via_tor) {
351 if (options->UseBridges && type != BRIDGE_AUTHORITY) {
352 /* want to ask a running bridge for which we have a descriptor. */
353 /* XXX022 we assume that all of our bridges can answer any
354 * possible directory question. This won't be true forever. -RD */
355 /* It certainly is not true with conditional consensus downloading,
356 * so, for now, never assume the server supports that. */
357 routerinfo_t *ri = choose_random_entry(NULL);
358 if (ri) {
359 tor_addr_t addr;
360 tor_addr_from_ipv4h(&addr, ri->addr);
361 directory_initiate_command(ri->address, &addr,
362 ri->or_port, 0,
363 0, /* don't use conditional consensus url */
364 1, ri->cache_info.identity_digest,
365 dir_purpose,
366 router_purpose,
367 0, resource, NULL, 0, if_modified_since);
368 } else
369 log_notice(LD_DIR, "Ignoring directory request, since no bridge "
370 "nodes are available yet.");
371 return;
372 } else {
373 if (prefer_authority || type == BRIDGE_AUTHORITY) {
374 /* only ask authdirservers, and don't ask myself */
375 rs = router_pick_trusteddirserver(type, pds_flags);
376 if (rs == NULL && (pds_flags & PDS_NO_EXISTING_SERVERDESC_FETCH)) {
377 /* We don't want to fetch from any authorities that we're currently
378 * fetching server descriptors from, and we got no match. Did we
379 * get no match because all the authorities have connections
380 * fetching server descriptors (in which case we should just
381 * return,) or because all the authorities are down or on fire or
382 * unreachable or something (in which case we should go on with
383 * our fallback code)? */
384 pds_flags &= ~PDS_NO_EXISTING_SERVERDESC_FETCH;
385 rs = router_pick_trusteddirserver(type, pds_flags);
386 if (rs) {
387 log_debug(LD_DIR, "Deferring serverdesc fetch: all authorities "
388 "are in use.");
389 return;
393 if (!rs && type != BRIDGE_AUTHORITY) {
394 /* anybody with a non-zero dirport will do */
395 rs = router_pick_directory_server(type, pds_flags);
396 if (!rs) {
397 log_info(LD_DIR, "No router found for %s; falling back to "
398 "dirserver list.", dir_conn_purpose_to_string(dir_purpose));
399 rs = router_pick_trusteddirserver(type, pds_flags);
400 if (!rs)
401 get_via_tor = 1; /* last resort: try routing it via Tor */
405 } else { /* get_via_tor */
406 /* Never use fascistfirewall; we're going via Tor. */
407 if (dir_purpose == DIR_PURPOSE_FETCH_RENDDESC) {
408 /* only ask hidserv authorities, any of them will do */
409 pds_flags |= PDS_IGNORE_FASCISTFIREWALL|PDS_ALLOW_SELF;
410 rs = router_pick_trusteddirserver(HIDSERV_AUTHORITY, pds_flags);
411 } else {
412 /* anybody with a non-zero dirport will do. Disregard firewalls. */
413 pds_flags |= PDS_IGNORE_FASCISTFIREWALL;
414 rs = router_pick_directory_server(type, pds_flags);
415 /* If we have any hope of building an indirect conn, we know some router
416 * descriptors. If (rs==NULL), we can't build circuits anyway, so
417 * there's no point in falling back to the authorities in this case. */
421 if (rs)
422 directory_initiate_command_routerstatus(rs, dir_purpose,
423 router_purpose,
424 get_via_tor,
425 resource, NULL, 0,
426 if_modified_since);
427 else {
428 log_notice(LD_DIR,
429 "While fetching directory info, "
430 "no running dirservers known. Will try again later. "
431 "(purpose %d)", dir_purpose);
432 if (!purpose_needs_anonymity(dir_purpose, router_purpose)) {
433 /* remember we tried them all and failed. */
434 directory_all_unreachable(time(NULL));
439 /** As directory_get_from_dirserver, but initiates a request to <i>every</i>
440 * directory authority other than ourself. Only for use by authorities when
441 * searching for missing information while voting. */
442 void
443 directory_get_from_all_authorities(uint8_t dir_purpose,
444 uint8_t router_purpose,
445 const char *resource)
447 tor_assert(dir_purpose == DIR_PURPOSE_FETCH_STATUS_VOTE ||
448 dir_purpose == DIR_PURPOSE_FETCH_DETACHED_SIGNATURES);
450 SMARTLIST_FOREACH(router_get_trusted_dir_servers(),
451 trusted_dir_server_t *, ds,
453 routerstatus_t *rs;
454 if (router_digest_is_me(ds->digest))
455 continue;
456 if (!(ds->type & V3_AUTHORITY))
457 continue;
458 rs = &ds->fake_status;
459 directory_initiate_command_routerstatus(rs, dir_purpose, router_purpose,
460 0, resource, NULL, 0, 0);
464 /** Same as directory_initiate_command_routerstatus(), but accepts
465 * rendezvous data to fetch a hidden service descriptor. */
466 void
467 directory_initiate_command_routerstatus_rend(routerstatus_t *status,
468 uint8_t dir_purpose,
469 uint8_t router_purpose,
470 int anonymized_connection,
471 const char *resource,
472 const char *payload,
473 size_t payload_len,
474 time_t if_modified_since,
475 const rend_data_t *rend_query)
477 routerinfo_t *router;
478 char address_buf[INET_NTOA_BUF_LEN+1];
479 struct in_addr in;
480 const char *address;
481 tor_addr_t addr;
482 router = router_get_by_digest(status->identity_digest);
483 if (!router && anonymized_connection) {
484 log_info(LD_DIR, "Not sending anonymized request to directory '%s'; we "
485 "don't have its router descriptor.", status->nickname);
486 return;
487 } else if (router) {
488 address = router->address;
489 } else {
490 in.s_addr = htonl(status->addr);
491 tor_inet_ntoa(&in, address_buf, sizeof(address_buf));
492 address = address_buf;
494 tor_addr_from_ipv4h(&addr, status->addr);
495 directory_initiate_command_rend(address, &addr,
496 status->or_port, status->dir_port,
497 status->version_supports_conditional_consensus,
498 status->version_supports_begindir,
499 status->identity_digest,
500 dir_purpose, router_purpose,
501 anonymized_connection, resource,
502 payload, payload_len, if_modified_since,
503 rend_query);
506 /** Launch a new connection to the directory server <b>status</b> to
507 * upload or download a server or rendezvous
508 * descriptor. <b>dir_purpose</b> determines what
509 * kind of directory connection we're launching, and must be one of
510 * DIR_PURPOSE_{FETCH|UPLOAD}_{DIR|RENDDESC|RENDDESC_V2}. <b>router_purpose</b>
511 * specifies the descriptor purposes we have in mind (currently only
512 * used for FETCH_DIR).
514 * When uploading, <b>payload</b> and <b>payload_len</b> determine the content
515 * of the HTTP post. Otherwise, <b>payload</b> should be NULL.
517 * When fetching a rendezvous descriptor, <b>resource</b> is the service ID we
518 * want to fetch.
520 void
521 directory_initiate_command_routerstatus(routerstatus_t *status,
522 uint8_t dir_purpose,
523 uint8_t router_purpose,
524 int anonymized_connection,
525 const char *resource,
526 const char *payload,
527 size_t payload_len,
528 time_t if_modified_since)
530 directory_initiate_command_routerstatus_rend(status, dir_purpose,
531 router_purpose,
532 anonymized_connection, resource,
533 payload, payload_len,
534 if_modified_since, NULL);
537 /** Return true iff <b>conn</b> is the client side of a directory connection
538 * we launched to ourself in order to determine the reachability of our
539 * dir_port. */
540 static int
541 directory_conn_is_self_reachability_test(dir_connection_t *conn)
543 if (conn->requested_resource &&
544 !strcmpstart(conn->requested_resource,"authority")) {
545 routerinfo_t *me = router_get_my_routerinfo();
546 if (me &&
547 router_digest_is_me(conn->identity_digest) &&
548 tor_addr_eq_ipv4h(&conn->_base.addr, me->addr) && /*XXXX prop 118*/
549 me->dir_port == conn->_base.port)
550 return 1;
552 return 0;
555 /** Called when we are unable to complete the client's request to a directory
556 * server due to a network error: Mark the router as down and try again if
557 * possible.
559 void
560 connection_dir_request_failed(dir_connection_t *conn)
562 if (directory_conn_is_self_reachability_test(conn)) {
563 return; /* this was a test fetch. don't retry. */
565 if (entry_list_is_constrained(get_options()))
566 router_set_status(conn->identity_digest, 0); /* don't try him again */
567 if (conn->_base.purpose == DIR_PURPOSE_FETCH_V2_NETWORKSTATUS) {
568 log_info(LD_DIR, "Giving up on directory server at '%s'; retrying",
569 conn->_base.address);
570 connection_dir_download_networkstatus_failed(conn, -1);
571 } else if (conn->_base.purpose == DIR_PURPOSE_FETCH_SERVERDESC ||
572 conn->_base.purpose == DIR_PURPOSE_FETCH_EXTRAINFO) {
573 log_info(LD_DIR, "Giving up on directory server at '%s'; retrying",
574 conn->_base.address);
575 connection_dir_download_routerdesc_failed(conn);
576 } else if (conn->_base.purpose == DIR_PURPOSE_FETCH_CONSENSUS) {
577 networkstatus_consensus_download_failed(0);
578 } else if (conn->_base.purpose == DIR_PURPOSE_FETCH_CERTIFICATE) {
579 log_info(LD_DIR, "Giving up on directory server at '%s'; retrying",
580 conn->_base.address);
581 connection_dir_download_cert_failed(conn, 0);
582 } else if (conn->_base.purpose == DIR_PURPOSE_FETCH_DETACHED_SIGNATURES) {
583 log_info(LD_DIR, "Giving up downloading detached signatures from '%s'",
584 conn->_base.address);
585 } else if (conn->_base.purpose == DIR_PURPOSE_FETCH_STATUS_VOTE) {
586 log_info(LD_DIR, "Giving up downloading votes from '%s'",
587 conn->_base.address);
591 /** Called when an attempt to download one or more network status
592 * documents on connection <b>conn</b> failed. Decide whether to
593 * retry the fetch now, later, or never.
595 static void
596 connection_dir_download_networkstatus_failed(dir_connection_t *conn,
597 int status_code)
599 if (!conn->requested_resource) {
600 /* We never reached directory_send_command, which means that we never
601 * opened a network connection. Either we're out of sockets, or the
602 * network is down. Either way, retrying would be pointless. */
603 return;
605 if (!strcmpstart(conn->requested_resource, "all")) {
606 /* We're a non-authoritative directory cache; try again. Ignore status
607 * code, since we don't want to keep trying forever in a tight loop
608 * if all the authorities are shutting us out. */
609 smartlist_t *trusted_dirs = router_get_trusted_dir_servers();
610 SMARTLIST_FOREACH(trusted_dirs, trusted_dir_server_t *, ds,
611 download_status_failed(&ds->v2_ns_dl_status, 0));
612 directory_get_from_dirserver(conn->_base.purpose, conn->router_purpose,
613 "all.z", 0 /* don't retry_if_no_servers */);
614 } else if (!strcmpstart(conn->requested_resource, "fp/")) {
615 /* We were trying to download by fingerprint; mark them all as having
616 * failed, and possibly retry them later.*/
617 smartlist_t *failed = smartlist_create();
618 dir_split_resource_into_fingerprints(conn->requested_resource+3,
619 failed, NULL, 0);
620 if (smartlist_len(failed)) {
621 dir_networkstatus_download_failed(failed, status_code);
622 SMARTLIST_FOREACH(failed, char *, cp, tor_free(cp));
624 smartlist_free(failed);
628 /** Called when an attempt to download one or more router descriptors
629 * or extra-info documents on connection <b>conn</b> failed.
631 static void
632 connection_dir_download_routerdesc_failed(dir_connection_t *conn)
634 /* No need to increment the failure count for routerdescs, since
635 * it's not their fault. */
637 /* No need to relaunch descriptor downloads here: we already do it
638 * every 10 or 60 seconds (FOO_DESCRIPTOR_RETRY_INTERVAL) in main.c. */
639 tor_assert(conn->_base.purpose == DIR_PURPOSE_FETCH_SERVERDESC ||
640 conn->_base.purpose == DIR_PURPOSE_FETCH_EXTRAINFO);
642 (void) conn;
645 /** Called when an attempt to fetch a certificate fails. */
646 static void
647 connection_dir_download_cert_failed(dir_connection_t *conn, int status)
649 smartlist_t *failed;
650 tor_assert(conn->_base.purpose == DIR_PURPOSE_FETCH_CERTIFICATE);
652 if (!conn->requested_resource)
653 return;
654 failed = smartlist_create();
655 dir_split_resource_into_fingerprints(conn->requested_resource+3,
656 failed, NULL, DSR_HEX);
657 SMARTLIST_FOREACH(failed, char *, cp,
659 authority_cert_dl_failed(cp, status);
660 tor_free(cp);
662 smartlist_free(failed);
664 update_certificate_downloads(time(NULL));
667 /** Evaluate the situation and decide if we should use an encrypted
668 * "begindir-style" connection for this directory request.
669 * 1) If or_port is 0, or it's a direct conn and or_port is firewalled
670 * or we're a dir mirror, no.
671 * 2) If we prefer to avoid begindir conns, and we're not fetching or
672 * publishing a bridge relay descriptor, no.
673 * 3) Else yes.
675 static int
676 directory_command_should_use_begindir(or_options_t *options,
677 const tor_addr_t *addr,
678 int or_port, uint8_t router_purpose,
679 int anonymized_connection)
681 if (!or_port)
682 return 0; /* We don't know an ORPort -- no chance. */
683 if (!anonymized_connection)
684 if (!fascist_firewall_allows_address_or(addr, or_port) ||
685 directory_fetches_from_authorities(options) ||
686 (server_mode(options) && !options->Address))
687 return 0; /* We're firewalled or are acting like a relay -- also no. */
688 if (!options->TunnelDirConns &&
689 router_purpose != ROUTER_PURPOSE_BRIDGE)
690 return 0; /* We prefer to avoid using begindir conns. Fine. */
691 return 1;
694 /** Helper for directory_initiate_command_routerstatus: send the
695 * command to a server whose address is <b>address</b>, whose IP is
696 * <b>addr</b>, whose directory port is <b>dir_port</b>, whose tor version
697 * <b>supports_begindir</b>, and whose identity key digest is
698 * <b>digest</b>. */
699 void
700 directory_initiate_command(const char *address, const tor_addr_t *_addr,
701 uint16_t or_port, uint16_t dir_port,
702 int supports_conditional_consensus,
703 int supports_begindir, const char *digest,
704 uint8_t dir_purpose, uint8_t router_purpose,
705 int anonymized_connection, const char *resource,
706 const char *payload, size_t payload_len,
707 time_t if_modified_since)
709 directory_initiate_command_rend(address, _addr, or_port, dir_port,
710 supports_conditional_consensus,
711 supports_begindir, digest, dir_purpose,
712 router_purpose, anonymized_connection,
713 resource, payload, payload_len,
714 if_modified_since, NULL);
717 /** Same as directory_initiate_command(), but accepts rendezvous data to
718 * fetch a hidden service descriptor. */
719 static void
720 directory_initiate_command_rend(const char *address, const tor_addr_t *_addr,
721 uint16_t or_port, uint16_t dir_port,
722 int supports_conditional_consensus,
723 int supports_begindir, const char *digest,
724 uint8_t dir_purpose, uint8_t router_purpose,
725 int anonymized_connection,
726 const char *resource,
727 const char *payload, size_t payload_len,
728 time_t if_modified_since,
729 const rend_data_t *rend_query)
731 dir_connection_t *conn;
732 or_options_t *options = get_options();
733 int socket_error = 0;
734 int use_begindir = supports_begindir &&
735 directory_command_should_use_begindir(options, _addr,
736 or_port, router_purpose, anonymized_connection);
737 tor_addr_t addr;
739 tor_assert(address);
740 tor_assert(_addr);
741 tor_assert(or_port || dir_port);
742 tor_assert(digest);
744 tor_addr_copy(&addr, _addr);
746 log_debug(LD_DIR, "anonymized %d, use_begindir %d.",
747 anonymized_connection, use_begindir);
749 log_debug(LD_DIR, "Initiating %s", dir_conn_purpose_to_string(dir_purpose));
751 /* ensure that we don't make direct connections when a SOCKS server is
752 * configured. */
753 if (!anonymized_connection && !use_begindir && !options->HttpProxy &&
754 (options->Socks4Proxy || options->Socks5Proxy)) {
755 log_warn(LD_DIR, "Cannot connect to a directory server through a "
756 "SOCKS proxy!");
757 return;
760 conn = dir_connection_new(AF_INET);
762 /* set up conn so it's got all the data we need to remember */
763 tor_addr_copy(&conn->_base.addr, &addr);
764 conn->_base.port = use_begindir ? or_port : dir_port;
765 conn->_base.address = tor_strdup(address);
766 memcpy(conn->identity_digest, digest, DIGEST_LEN);
768 conn->_base.purpose = dir_purpose;
769 conn->router_purpose = router_purpose;
771 /* give it an initial state */
772 conn->_base.state = DIR_CONN_STATE_CONNECTING;
774 /* decide whether we can learn our IP address from this conn */
775 conn->dirconn_direct = !anonymized_connection;
777 /* copy rendezvous data, if any */
778 if (rend_query)
779 conn->rend_data = rend_data_dup(rend_query);
781 if (!anonymized_connection && !use_begindir) {
782 /* then we want to connect to dirport directly */
784 if (options->HttpProxy) {
785 tor_addr_copy(&addr, &options->HttpProxyAddr);
786 dir_port = options->HttpProxyPort;
789 switch (connection_connect(TO_CONN(conn), conn->_base.address, &addr,
790 dir_port, &socket_error)) {
791 case -1:
792 connection_dir_request_failed(conn); /* retry if we want */
793 /* XXX we only pass 'conn' above, not 'resource', 'payload',
794 * etc. So in many situations it can't retry! -RD */
795 connection_free(TO_CONN(conn));
796 return;
797 case 1:
798 /* start flushing conn */
799 conn->_base.state = DIR_CONN_STATE_CLIENT_SENDING;
800 /* fall through */
801 case 0:
802 /* queue the command on the outbuf */
803 directory_send_command(conn, dir_purpose, 1, resource,
804 payload, payload_len,
805 supports_conditional_consensus,
806 if_modified_since);
807 connection_watch_events(TO_CONN(conn), READ_EVENT | WRITE_EVENT);
808 /* writable indicates finish, readable indicates broken link,
809 error indicates broken link in windowsland. */
811 } else { /* we want to connect via a tor connection */
812 edge_connection_t *linked_conn;
814 /* If it's an anonymized connection, remember the fact that we
815 * wanted it for later: maybe we'll want it again soon. */
816 if (anonymized_connection && use_begindir)
817 rep_hist_note_used_internal(time(NULL), 0, 1);
818 else if (anonymized_connection && !use_begindir)
819 rep_hist_note_used_port(time(NULL), conn->_base.port);
821 /* make an AP connection
822 * populate it and add it at the right state
823 * hook up both sides
825 linked_conn =
826 connection_ap_make_link(conn->_base.address, conn->_base.port,
827 digest, use_begindir, conn->dirconn_direct);
828 if (!linked_conn) {
829 log_warn(LD_NET,"Making tunnel to dirserver failed.");
830 connection_mark_for_close(TO_CONN(conn));
831 return;
833 connection_link_connections(TO_CONN(conn), TO_CONN(linked_conn));
835 if (connection_add(TO_CONN(conn)) < 0) {
836 log_warn(LD_NET,"Unable to add connection for link to dirserver.");
837 connection_mark_for_close(TO_CONN(conn));
838 return;
840 conn->_base.state = DIR_CONN_STATE_CLIENT_SENDING;
841 /* queue the command on the outbuf */
842 directory_send_command(conn, dir_purpose, 0, resource,
843 payload, payload_len,
844 supports_conditional_consensus,
845 if_modified_since);
846 connection_watch_events(TO_CONN(conn), READ_EVENT|WRITE_EVENT);
847 connection_start_reading(TO_CONN(linked_conn));
851 /** Return true iff anything we say on <b>conn</b> is being encrypted before
852 * we send it to the client/server. */
854 connection_dir_is_encrypted(dir_connection_t *conn)
856 /* Right now it's sufficient to see if conn is or has been linked, since
857 * the only thing it could be linked to is an edge connection on a
858 * circuit, and the only way it could have been unlinked is at the edge
859 * connection getting closed.
861 return TO_CONN(conn)->linked;
864 /** Helper for sorting
866 * sort strings alphabetically
868 static int
869 _compare_strs(const void **a, const void **b)
871 const char *s1 = *a, *s2 = *b;
872 return strcmp(s1, s2);
875 #define CONDITIONAL_CONSENSUS_FPR_LEN 3
876 #if (CONDITIONAL_CONSENSUS_FPR_LEN > DIGEST_LEN)
877 #error "conditional consensus fingerprint length is larger than digest length"
878 #endif
880 /** Return the URL we should use for a consensus download.
882 * This url depends on whether or not the server we go to
883 * is sufficiently new to support conditional consensus downloading,
884 * i.e. GET .../consensus/<b>fpr</b>+<b>fpr</b>+<b>fpr</b>
886 static char *
887 directory_get_consensus_url(int supports_conditional_consensus)
889 char *url;
890 size_t len;
892 if (supports_conditional_consensus) {
893 char *authority_id_list;
894 smartlist_t *authority_digests = smartlist_create();
896 SMARTLIST_FOREACH(router_get_trusted_dir_servers(),
897 trusted_dir_server_t *, ds,
899 char *hex;
900 if (!(ds->type & V3_AUTHORITY))
901 continue;
903 hex = tor_malloc(2*CONDITIONAL_CONSENSUS_FPR_LEN+1);
904 base16_encode(hex, 2*CONDITIONAL_CONSENSUS_FPR_LEN+1,
905 ds->v3_identity_digest, CONDITIONAL_CONSENSUS_FPR_LEN);
906 smartlist_add(authority_digests, hex);
908 smartlist_sort(authority_digests, _compare_strs);
909 authority_id_list = smartlist_join_strings(authority_digests,
910 "+", 0, NULL);
912 len = strlen(authority_id_list)+64;
913 url = tor_malloc(len);
914 tor_snprintf(url, len, "/tor/status-vote/current/consensus/%s.z",
915 authority_id_list);
917 SMARTLIST_FOREACH(authority_digests, char *, cp, tor_free(cp));
918 smartlist_free(authority_digests);
919 tor_free(authority_id_list);
920 } else {
921 url = tor_strdup("/tor/status-vote/current/consensus.z");
923 return url;
926 /** Queue an appropriate HTTP command on conn-\>outbuf. The other args
927 * are as in directory_initiate_command().
929 static void
930 directory_send_command(dir_connection_t *conn,
931 int purpose, int direct, const char *resource,
932 const char *payload, size_t payload_len,
933 int supports_conditional_consensus,
934 time_t if_modified_since)
936 char proxystring[256];
937 char proxyauthstring[256];
938 char hoststring[128];
939 char imsstring[RFC1123_TIME_LEN+32];
940 char *url;
941 char request[8192];
942 const char *httpcommand = NULL;
943 size_t len;
945 tor_assert(conn);
946 tor_assert(conn->_base.type == CONN_TYPE_DIR);
948 tor_free(conn->requested_resource);
949 if (resource)
950 conn->requested_resource = tor_strdup(resource);
952 /* come up with a string for which Host: we want */
953 if (conn->_base.port == 80) {
954 strlcpy(hoststring, conn->_base.address, sizeof(hoststring));
955 } else {
956 tor_snprintf(hoststring, sizeof(hoststring),"%s:%d",
957 conn->_base.address, conn->_base.port);
960 /* Format if-modified-since */
961 if (!if_modified_since) {
962 imsstring[0] = '\0';
963 } else {
964 char b[RFC1123_TIME_LEN+1];
965 format_rfc1123_time(b, if_modified_since);
966 tor_snprintf(imsstring, sizeof(imsstring), "\r\nIf-Modified-Since: %s", b);
969 /* come up with some proxy lines, if we're using one. */
970 if (direct && get_options()->HttpProxy) {
971 char *base64_authenticator=NULL;
972 const char *authenticator = get_options()->HttpProxyAuthenticator;
974 tor_snprintf(proxystring, sizeof(proxystring),"http://%s", hoststring);
975 if (authenticator) {
976 base64_authenticator = alloc_http_authenticator(authenticator);
977 if (!base64_authenticator)
978 log_warn(LD_BUG, "Encoding http authenticator failed");
980 if (base64_authenticator) {
981 tor_snprintf(proxyauthstring, sizeof(proxyauthstring),
982 "\r\nProxy-Authorization: Basic %s",
983 base64_authenticator);
984 tor_free(base64_authenticator);
985 } else {
986 proxyauthstring[0] = 0;
988 } else {
989 proxystring[0] = 0;
990 proxyauthstring[0] = 0;
993 switch (purpose) {
994 case DIR_PURPOSE_FETCH_V2_NETWORKSTATUS:
995 tor_assert(resource);
996 httpcommand = "GET";
997 len = strlen(resource)+32;
998 url = tor_malloc(len);
999 tor_snprintf(url, len, "/tor/status/%s", resource);
1000 break;
1001 case DIR_PURPOSE_FETCH_CONSENSUS:
1002 tor_assert(!resource);
1003 tor_assert(!payload);
1004 httpcommand = "GET";
1005 url = directory_get_consensus_url(supports_conditional_consensus);
1006 log_info(LD_DIR, "Downloading consensus from %s using %s",
1007 hoststring, url);
1008 break;
1009 case DIR_PURPOSE_FETCH_CERTIFICATE:
1010 tor_assert(resource);
1011 tor_assert(!payload);
1012 httpcommand = "GET";
1013 len = strlen(resource)+32;
1014 url = tor_malloc(len);
1015 tor_snprintf(url, len, "/tor/keys/%s", resource);
1016 break;
1017 case DIR_PURPOSE_FETCH_STATUS_VOTE:
1018 tor_assert(resource);
1019 tor_assert(!payload);
1020 httpcommand = "GET";
1021 len = strlen(resource)+32;
1022 url = tor_malloc(len);
1023 tor_snprintf(url, len, "/tor/status-vote/next/%s.z", resource);
1024 break;
1025 case DIR_PURPOSE_FETCH_DETACHED_SIGNATURES:
1026 tor_assert(!resource);
1027 tor_assert(!payload);
1028 httpcommand = "GET";
1029 url = tor_strdup("/tor/status-vote/next/consensus-signatures.z");
1030 break;
1031 case DIR_PURPOSE_FETCH_SERVERDESC:
1032 tor_assert(resource);
1033 httpcommand = "GET";
1034 len = strlen(resource)+32;
1035 url = tor_malloc(len);
1036 tor_snprintf(url, len, "/tor/server/%s", resource);
1037 break;
1038 case DIR_PURPOSE_FETCH_EXTRAINFO:
1039 tor_assert(resource);
1040 httpcommand = "GET";
1041 len = strlen(resource)+32;
1042 url = tor_malloc(len);
1043 tor_snprintf(url, len, "/tor/extra/%s", resource);
1044 break;
1045 case DIR_PURPOSE_UPLOAD_DIR:
1046 tor_assert(!resource);
1047 tor_assert(payload);
1048 httpcommand = "POST";
1049 url = tor_strdup("/tor/");
1050 break;
1051 case DIR_PURPOSE_UPLOAD_VOTE:
1052 tor_assert(!resource);
1053 tor_assert(payload);
1054 httpcommand = "POST";
1055 url = tor_strdup("/tor/post/vote");
1056 break;
1057 case DIR_PURPOSE_UPLOAD_SIGNATURES:
1058 tor_assert(!resource);
1059 tor_assert(payload);
1060 httpcommand = "POST";
1061 url = tor_strdup("/tor/post/consensus-signature");
1062 break;
1063 case DIR_PURPOSE_FETCH_RENDDESC_V2:
1064 tor_assert(resource);
1065 tor_assert(strlen(resource) <= REND_DESC_ID_V2_LEN_BASE32);
1066 tor_assert(!payload);
1067 httpcommand = "GET";
1068 len = strlen(resource) + 32;
1069 url = tor_malloc(len);
1070 tor_snprintf(url, len, "/tor/rendezvous2/%s", resource);
1071 break;
1072 case DIR_PURPOSE_UPLOAD_RENDDESC:
1073 tor_assert(!resource);
1074 tor_assert(payload);
1075 httpcommand = "POST";
1076 url = tor_strdup("/tor/rendezvous/publish");
1077 break;
1078 case DIR_PURPOSE_UPLOAD_RENDDESC_V2:
1079 tor_assert(!resource);
1080 tor_assert(payload);
1081 httpcommand = "POST";
1082 url = tor_strdup("/tor/rendezvous2/publish");
1083 break;
1084 default:
1085 tor_assert(0);
1086 return;
1089 if (strlen(proxystring) + strlen(url) >= 4096) {
1090 log_warn(LD_BUG,
1091 "Squid does not like URLs longer than 4095 bytes, and this "
1092 "one is %d bytes long: %s%s",
1093 (int)(strlen(proxystring) + strlen(url)), proxystring, url);
1096 tor_snprintf(request, sizeof(request), "%s %s", httpcommand, proxystring);
1097 connection_write_to_buf(request, strlen(request), TO_CONN(conn));
1098 connection_write_to_buf(url, strlen(url), TO_CONN(conn));
1099 tor_free(url);
1101 if (!strcmp(httpcommand, "GET") && !payload) {
1102 tor_snprintf(request, sizeof(request),
1103 " HTTP/1.0\r\nHost: %s%s%s\r\n\r\n",
1104 hoststring,
1105 imsstring,
1106 proxyauthstring);
1107 } else {
1108 tor_snprintf(request, sizeof(request),
1109 " HTTP/1.0\r\nContent-Length: %lu\r\nHost: %s%s%s\r\n\r\n",
1110 payload ? (unsigned long)payload_len : 0,
1111 hoststring,
1112 imsstring,
1113 proxyauthstring);
1115 connection_write_to_buf(request, strlen(request), TO_CONN(conn));
1117 if (payload) {
1118 /* then send the payload afterwards too */
1119 connection_write_to_buf(payload, payload_len, TO_CONN(conn));
1123 /** Parse an HTTP request string <b>headers</b> of the form
1124 * \verbatim
1125 * "\%s [http[s]://]\%s HTTP/1..."
1126 * \endverbatim
1127 * If it's well-formed, strdup the second \%s into *<b>url</b>, and
1128 * nul-terminate it. If the url doesn't start with "/tor/", rewrite it
1129 * so it does. Return 0.
1130 * Otherwise, return -1.
1132 static int
1133 parse_http_url(const char *headers, char **url)
1135 char *s, *start, *tmp;
1137 s = (char *)eat_whitespace_no_nl(headers);
1138 if (!*s) return -1;
1139 s = (char *)find_whitespace(s); /* get past GET/POST */
1140 if (!*s) return -1;
1141 s = (char *)eat_whitespace_no_nl(s);
1142 if (!*s) return -1;
1143 start = s; /* this is it, assuming it's valid */
1144 s = (char *)find_whitespace(start);
1145 if (!*s) return -1;
1147 /* tolerate the http[s] proxy style of putting the hostname in the url */
1148 if (s-start >= 4 && !strcmpstart(start,"http")) {
1149 tmp = start + 4;
1150 if (*tmp == 's')
1151 tmp++;
1152 if (s-tmp >= 3 && !strcmpstart(tmp,"://")) {
1153 tmp = strchr(tmp+3, '/');
1154 if (tmp && tmp < s) {
1155 log_debug(LD_DIR,"Skipping over 'http[s]://hostname/' string");
1156 start = tmp;
1161 if (s-start < 5 || strcmpstart(start,"/tor/")) { /* need to rewrite it */
1162 *url = tor_malloc(s - start + 5);
1163 strlcpy(*url,"/tor", s-start+5);
1164 strlcat((*url)+4, start, s-start+1);
1165 } else {
1166 *url = tor_strndup(start, s-start);
1168 return 0;
1171 /** Return a copy of the first HTTP header in <b>headers</b> whose key is
1172 * <b>which</b>. The key should be given with a terminating colon and space;
1173 * this function copies everything after, up to but not including the
1174 * following \\r\\n. */
1175 static char *
1176 http_get_header(const char *headers, const char *which)
1178 const char *cp = headers;
1179 while (cp) {
1180 if (!strcasecmpstart(cp, which)) {
1181 char *eos;
1182 cp += strlen(which);
1183 if ((eos = strchr(cp,'\r')))
1184 return tor_strndup(cp, eos-cp);
1185 else
1186 return tor_strdup(cp);
1188 cp = strchr(cp, '\n');
1189 if (cp)
1190 ++cp;
1192 return NULL;
1195 /** If <b>headers</b> indicates that a proxy was involved, then rewrite
1196 * <b>conn</b>-\>address to describe our best guess of the address that
1197 * originated this HTTP request. */
1198 static void
1199 http_set_address_origin(const char *headers, connection_t *conn)
1201 char *fwd;
1203 fwd = http_get_header(headers, "Forwarded-For: ");
1204 if (!fwd)
1205 fwd = http_get_header(headers, "X-Forwarded-For: ");
1206 if (fwd) {
1207 struct in_addr in;
1208 if (!tor_inet_aton(fwd, &in) || is_internal_IP(ntohl(in.s_addr), 0)) {
1209 log_debug(LD_DIR, "Ignoring unrecognized or internal IP %s",
1210 escaped(fwd));
1211 tor_free(fwd);
1212 return;
1214 tor_free(conn->address);
1215 conn->address = tor_strdup(fwd);
1216 tor_free(fwd);
1220 /** Parse an HTTP response string <b>headers</b> of the form
1221 * \verbatim
1222 * "HTTP/1.\%d \%d\%s\r\n...".
1223 * \endverbatim
1225 * If it's well-formed, assign the status code to *<b>code</b> and
1226 * return 0. Otherwise, return -1.
1228 * On success: If <b>date</b> is provided, set *date to the Date
1229 * header in the http headers, or 0 if no such header is found. If
1230 * <b>compression</b> is provided, set *<b>compression</b> to the
1231 * compression method given in the Content-Encoding header, or 0 if no
1232 * such header is found, or -1 if the value of the header is not
1233 * recognized. If <b>reason</b> is provided, strdup the reason string
1234 * into it.
1237 parse_http_response(const char *headers, int *code, time_t *date,
1238 compress_method_t *compression, char **reason)
1240 unsigned n1, n2;
1241 char datestr[RFC1123_TIME_LEN+1];
1242 smartlist_t *parsed_headers;
1243 tor_assert(headers);
1244 tor_assert(code);
1246 while (TOR_ISSPACE(*headers)) headers++; /* tolerate leading whitespace */
1248 if (tor_sscanf(headers, "HTTP/1.%u %u", &n1, &n2) < 2 ||
1249 (n1 != 0 && n1 != 1) ||
1250 (n2 < 100 || n2 >= 600)) {
1251 log_warn(LD_HTTP,"Failed to parse header %s",escaped(headers));
1252 return -1;
1254 *code = n2;
1256 parsed_headers = smartlist_create();
1257 smartlist_split_string(parsed_headers, headers, "\n",
1258 SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
1259 if (reason) {
1260 smartlist_t *status_line_elements = smartlist_create();
1261 tor_assert(smartlist_len(parsed_headers));
1262 smartlist_split_string(status_line_elements,
1263 smartlist_get(parsed_headers, 0),
1264 " ", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 3);
1265 tor_assert(smartlist_len(status_line_elements) <= 3);
1266 if (smartlist_len(status_line_elements) == 3) {
1267 *reason = smartlist_get(status_line_elements, 2);
1268 smartlist_set(status_line_elements, 2, NULL); /* Prevent free */
1270 SMARTLIST_FOREACH(status_line_elements, char *, cp, tor_free(cp));
1271 smartlist_free(status_line_elements);
1273 if (date) {
1274 *date = 0;
1275 SMARTLIST_FOREACH(parsed_headers, const char *, s,
1276 if (!strcmpstart(s, "Date: ")) {
1277 strlcpy(datestr, s+6, sizeof(datestr));
1278 /* This will do nothing on failure, so we don't need to check
1279 the result. We shouldn't warn, since there are many other valid
1280 date formats besides the one we use. */
1281 parse_rfc1123_time(datestr, date);
1282 break;
1285 if (compression) {
1286 const char *enc = NULL;
1287 SMARTLIST_FOREACH(parsed_headers, const char *, s,
1288 if (!strcmpstart(s, "Content-Encoding: ")) {
1289 enc = s+18; break;
1291 if (!enc || !strcmp(enc, "identity")) {
1292 *compression = NO_METHOD;
1293 } else if (!strcmp(enc, "deflate") || !strcmp(enc, "x-deflate")) {
1294 *compression = ZLIB_METHOD;
1295 } else if (!strcmp(enc, "gzip") || !strcmp(enc, "x-gzip")) {
1296 *compression = GZIP_METHOD;
1297 } else {
1298 log_info(LD_HTTP, "Unrecognized content encoding: %s. Trying to deal.",
1299 escaped(enc));
1300 *compression = UNKNOWN_METHOD;
1303 SMARTLIST_FOREACH(parsed_headers, char *, s, tor_free(s));
1304 smartlist_free(parsed_headers);
1306 return 0;
1309 /** Return true iff <b>body</b> doesn't start with a plausible router or
1310 * running-list or directory opening. This is a sign of possible compression.
1312 static int
1313 body_is_plausible(const char *body, size_t len, int purpose)
1315 int i;
1316 if (len == 0)
1317 return 1; /* empty bodies don't need decompression */
1318 if (len < 32)
1319 return 0;
1320 if (purpose != DIR_PURPOSE_FETCH_RENDDESC) {
1321 if (!strcmpstart(body,"router") ||
1322 !strcmpstart(body,"signed-directory") ||
1323 !strcmpstart(body,"network-status") ||
1324 !strcmpstart(body,"running-routers"))
1325 return 1;
1326 for (i=0;i<32;++i) {
1327 if (!TOR_ISPRINT(body[i]) && !TOR_ISSPACE(body[i]))
1328 return 0;
1330 return 1;
1331 } else {
1332 return 1;
1336 /** Called when we've just fetched a bunch of router descriptors in
1337 * <b>body</b>. The list <b>which</b>, if present, holds digests for
1338 * descriptors we requested: descriptor digests if <b>descriptor_digests</b>
1339 * is true, or identity digests otherwise. Parse the descriptors, validate
1340 * them, and annotate them as having purpose <b>purpose</b> and as having been
1341 * downloaded from <b>source</b>.
1343 * Return the number of routers actually added. */
1344 static int
1345 load_downloaded_routers(const char *body, smartlist_t *which,
1346 int descriptor_digests,
1347 int router_purpose,
1348 const char *source)
1350 char buf[256];
1351 char time_buf[ISO_TIME_LEN+1];
1352 int added = 0;
1353 int general = router_purpose == ROUTER_PURPOSE_GENERAL;
1354 format_iso_time(time_buf, time(NULL));
1355 tor_assert(source);
1357 if (tor_snprintf(buf, sizeof(buf),
1358 "@downloaded-at %s\n"
1359 "@source %s\n"
1360 "%s%s%s", time_buf, escaped(source),
1361 !general ? "@purpose " : "",
1362 !general ? router_purpose_to_string(router_purpose) : "",
1363 !general ? "\n" : "")<0)
1364 return added;
1366 added = router_load_routers_from_string(body, NULL, SAVED_NOWHERE, which,
1367 descriptor_digests, buf);
1368 control_event_bootstrap(BOOTSTRAP_STATUS_LOADING_DESCRIPTORS,
1369 count_loading_descriptors_progress());
1370 return added;
1373 /** We are a client, and we've finished reading the server's
1374 * response. Parse it and act appropriately.
1376 * If we're still happy with using this directory server in the future, return
1377 * 0. Otherwise return -1; and the caller should consider trying the request
1378 * again.
1380 * The caller will take care of marking the connection for close.
1382 static int
1383 connection_dir_client_reached_eof(dir_connection_t *conn)
1385 char *body;
1386 char *headers;
1387 char *reason = NULL;
1388 size_t body_len=0, orig_len=0;
1389 int status_code;
1390 time_t date_header=0;
1391 long delta;
1392 compress_method_t compression;
1393 int plausible;
1394 int skewed=0;
1395 int allow_partial = (conn->_base.purpose == DIR_PURPOSE_FETCH_SERVERDESC ||
1396 conn->_base.purpose == DIR_PURPOSE_FETCH_EXTRAINFO);
1397 int was_compressed=0;
1398 time_t now = time(NULL);
1400 switch (fetch_from_buf_http(conn->_base.inbuf,
1401 &headers, MAX_HEADERS_SIZE,
1402 &body, &body_len, MAX_DIR_DL_SIZE,
1403 allow_partial)) {
1404 case -1: /* overflow */
1405 log_warn(LD_PROTOCOL,
1406 "'fetch' response too large (server '%s:%d'). Closing.",
1407 conn->_base.address, conn->_base.port);
1408 return -1;
1409 case 0:
1410 log_info(LD_HTTP,
1411 "'fetch' response not all here, but we're at eof. Closing.");
1412 return -1;
1413 /* case 1, fall through */
1415 orig_len = body_len;
1417 if (parse_http_response(headers, &status_code, &date_header,
1418 &compression, &reason) < 0) {
1419 log_warn(LD_HTTP,"Unparseable headers (server '%s:%d'). Closing.",
1420 conn->_base.address, conn->_base.port);
1421 tor_free(body); tor_free(headers);
1422 return -1;
1424 if (!reason) reason = tor_strdup("[no reason given]");
1426 log_debug(LD_DIR,
1427 "Received response from directory server '%s:%d': %d %s",
1428 conn->_base.address, conn->_base.port, status_code,
1429 escaped(reason));
1431 /* now check if it's got any hints for us about our IP address. */
1432 if (conn->dirconn_direct) {
1433 char *guess = http_get_header(headers, X_ADDRESS_HEADER);
1434 if (guess) {
1435 router_new_address_suggestion(guess, conn);
1436 tor_free(guess);
1440 if (date_header > 0) {
1441 /* The date header was written very soon after we sent our request,
1442 * so compute the skew as the difference between sending the request
1443 * and the date header. (We used to check now-date_header, but that's
1444 * inaccurate if we spend a lot of time downloading.)
1446 delta = conn->_base.timestamp_lastwritten - date_header;
1447 if (labs(delta)>ALLOW_DIRECTORY_TIME_SKEW) {
1448 char dbuf[64];
1449 int trusted = router_digest_is_trusted_dir(conn->identity_digest);
1450 format_time_interval(dbuf, sizeof(dbuf), delta);
1451 log_fn(trusted ? LOG_WARN : LOG_INFO,
1452 LD_HTTP,
1453 "Received directory with skewed time (server '%s:%d'): "
1454 "It seems that our clock is %s by %s, or that theirs is %s. "
1455 "Tor requires an accurate clock to work: please check your time, "
1456 "timezone, and date settings.",
1457 conn->_base.address, conn->_base.port,
1458 delta>0 ? "ahead" : "behind", dbuf,
1459 delta>0 ? "behind" : "ahead");
1460 skewed = 1; /* don't check the recommended-versions line */
1461 control_event_general_status(trusted ? LOG_WARN : LOG_NOTICE,
1462 "CLOCK_SKEW SKEW=%ld SOURCE=DIRSERV:%s:%d",
1463 delta, conn->_base.address, conn->_base.port);
1464 } else {
1465 log_debug(LD_HTTP, "Time on received directory is within tolerance; "
1466 "we are %ld seconds skewed. (That's okay.)", delta);
1469 (void) skewed; /* skewed isn't used yet. */
1471 if (status_code == 503) {
1472 if (body_len < 16) {
1473 routerstatus_t *rs;
1474 trusted_dir_server_t *ds;
1475 log_info(LD_DIR,"Received http status code %d (%s) from server "
1476 "'%s:%d'. I'll try again soon.",
1477 status_code, escaped(reason), conn->_base.address,
1478 conn->_base.port);
1479 if ((rs = router_get_consensus_status_by_id(conn->identity_digest)))
1480 rs->last_dir_503_at = now;
1481 if ((ds = router_get_trusteddirserver_by_digest(conn->identity_digest)))
1482 ds->fake_status.last_dir_503_at = now;
1484 tor_free(body); tor_free(headers); tor_free(reason);
1485 return -1;
1487 /* XXXX022 Remove this once every server with bug 539 is obsolete. */
1488 log_info(LD_DIR, "Server at '%s:%d' sent us a 503 response, but included "
1489 "a body anyway. We'll pretend it gave us a 200.",
1490 conn->_base.address, conn->_base.port);
1491 status_code = 200;
1494 plausible = body_is_plausible(body, body_len, conn->_base.purpose);
1495 if (compression != NO_METHOD || !plausible) {
1496 char *new_body = NULL;
1497 size_t new_len = 0;
1498 compress_method_t guessed = detect_compression_method(body, body_len);
1499 if (compression == UNKNOWN_METHOD || guessed != compression) {
1500 /* Tell the user if we don't believe what we're told about compression.*/
1501 const char *description1, *description2;
1502 if (compression == ZLIB_METHOD)
1503 description1 = "as deflated";
1504 else if (compression == GZIP_METHOD)
1505 description1 = "as gzipped";
1506 else if (compression == NO_METHOD)
1507 description1 = "as uncompressed";
1508 else
1509 description1 = "with an unknown Content-Encoding";
1510 if (guessed == ZLIB_METHOD)
1511 description2 = "deflated";
1512 else if (guessed == GZIP_METHOD)
1513 description2 = "gzipped";
1514 else if (!plausible)
1515 description2 = "confusing binary junk";
1516 else
1517 description2 = "uncompressed";
1519 log_info(LD_HTTP, "HTTP body from server '%s:%d' was labeled %s, "
1520 "but it seems to be %s.%s",
1521 conn->_base.address, conn->_base.port, description1,
1522 description2,
1523 (compression>0 && guessed>0)?" Trying both.":"");
1525 /* Try declared compression first if we can. */
1526 if (compression == GZIP_METHOD || compression == ZLIB_METHOD)
1527 tor_gzip_uncompress(&new_body, &new_len, body, body_len, compression,
1528 !allow_partial, LOG_PROTOCOL_WARN);
1529 /* Okay, if that didn't work, and we think that it was compressed
1530 * differently, try that. */
1531 if (!new_body &&
1532 (guessed == GZIP_METHOD || guessed == ZLIB_METHOD) &&
1533 compression != guessed)
1534 tor_gzip_uncompress(&new_body, &new_len, body, body_len, guessed,
1535 !allow_partial, LOG_PROTOCOL_WARN);
1536 /* If we're pretty sure that we have a compressed directory, and
1537 * we didn't manage to uncompress it, then warn and bail. */
1538 if (!plausible && !new_body) {
1539 log_fn(LOG_PROTOCOL_WARN, LD_HTTP,
1540 "Unable to decompress HTTP body (server '%s:%d').",
1541 conn->_base.address, conn->_base.port);
1542 tor_free(body); tor_free(headers); tor_free(reason);
1543 return -1;
1545 if (new_body) {
1546 tor_free(body);
1547 body = new_body;
1548 body_len = new_len;
1549 was_compressed = 1;
1553 if (conn->_base.purpose == DIR_PURPOSE_FETCH_V2_NETWORKSTATUS) {
1554 smartlist_t *which = NULL;
1555 v2_networkstatus_source_t source;
1556 char *cp;
1557 log_info(LD_DIR,"Received networkstatus objects (size %d) from server "
1558 "'%s:%d'", (int)body_len, conn->_base.address, conn->_base.port);
1559 if (status_code != 200) {
1560 log_warn(LD_DIR,
1561 "Received http status code %d (%s) from server "
1562 "'%s:%d' while fetching \"/tor/status/%s\". I'll try again soon.",
1563 status_code, escaped(reason), conn->_base.address,
1564 conn->_base.port, conn->requested_resource);
1565 tor_free(body); tor_free(headers); tor_free(reason);
1566 connection_dir_download_networkstatus_failed(conn, status_code);
1567 return -1;
1569 if (conn->requested_resource &&
1570 !strcmpstart(conn->requested_resource,"fp/")) {
1571 source = NS_FROM_DIR_BY_FP;
1572 which = smartlist_create();
1573 dir_split_resource_into_fingerprints(conn->requested_resource+3,
1574 which, NULL, 0);
1575 } else if (conn->requested_resource &&
1576 !strcmpstart(conn->requested_resource, "all")) {
1577 source = NS_FROM_DIR_ALL;
1578 which = smartlist_create();
1579 SMARTLIST_FOREACH(router_get_trusted_dir_servers(),
1580 trusted_dir_server_t *, ds,
1582 char *hex = tor_malloc(HEX_DIGEST_LEN+1);
1583 base16_encode(hex, HEX_DIGEST_LEN+1, ds->digest, DIGEST_LEN);
1584 smartlist_add(which, hex);
1586 } else {
1587 /* XXXX Can we even end up here? -- weasel*/
1588 source = NS_FROM_DIR_BY_FP;
1589 log_warn(LD_BUG, "We received a networkstatus but we didn't ask "
1590 "for it by fp, nor did we ask for all.");
1592 cp = body;
1593 while (*cp) {
1594 char *next = strstr(cp, "\nnetwork-status-version");
1595 if (next)
1596 next[1] = '\0';
1597 /* learn from it, and then remove it from 'which' */
1598 if (router_set_networkstatus_v2(cp, now, source, which)<0)
1599 break;
1600 if (next) {
1601 next[1] = 'n';
1602 cp = next+1;
1603 } else
1604 break;
1606 /* launches router downloads as needed */
1607 routers_update_all_from_networkstatus(now, 2);
1608 directory_info_has_arrived(now, 0);
1609 if (which) {
1610 if (smartlist_len(which)) {
1611 dir_networkstatus_download_failed(which, status_code);
1613 SMARTLIST_FOREACH(which, char *, s, tor_free(s));
1614 smartlist_free(which);
1618 if (conn->_base.purpose == DIR_PURPOSE_FETCH_CONSENSUS) {
1619 int r;
1620 if (status_code != 200) {
1621 int severity = (status_code == 304) ? LOG_INFO : LOG_WARN;
1622 log(severity, LD_DIR,
1623 "Received http status code %d (%s) from server "
1624 "'%s:%d' while fetching consensus directory.",
1625 status_code, escaped(reason), conn->_base.address,
1626 conn->_base.port);
1627 tor_free(body); tor_free(headers); tor_free(reason);
1628 networkstatus_consensus_download_failed(status_code);
1629 return -1;
1631 log_info(LD_DIR,"Received consensus directory (size %d) from server "
1632 "'%s:%d'", (int)body_len, conn->_base.address, conn->_base.port);
1633 if ((r=networkstatus_set_current_consensus(body, "ns", 0))<0) {
1634 log_fn(r<-1?LOG_WARN:LOG_INFO, LD_DIR,
1635 "Unable to load consensus directory downloaded from "
1636 "server '%s:%d'. I'll try again soon.",
1637 conn->_base.address, conn->_base.port);
1638 tor_free(body); tor_free(headers); tor_free(reason);
1639 networkstatus_consensus_download_failed(0);
1640 return -1;
1642 /* launches router downloads as needed */
1643 routers_update_all_from_networkstatus(now, 3);
1644 directory_info_has_arrived(now, 0);
1645 log_info(LD_DIR, "Successfully loaded consensus.");
1648 if (conn->_base.purpose == DIR_PURPOSE_FETCH_CERTIFICATE) {
1649 if (status_code != 200) {
1650 log_warn(LD_DIR,
1651 "Received http status code %d (%s) from server "
1652 "'%s:%d' while fetching \"/tor/keys/%s\".",
1653 status_code, escaped(reason), conn->_base.address,
1654 conn->_base.port, conn->requested_resource);
1655 connection_dir_download_cert_failed(conn, status_code);
1656 tor_free(body); tor_free(headers); tor_free(reason);
1657 return -1;
1659 log_info(LD_DIR,"Received authority certificates (size %d) from server "
1660 "'%s:%d'", (int)body_len, conn->_base.address, conn->_base.port);
1661 if (trusted_dirs_load_certs_from_string(body, 0, 1)<0) {
1662 log_warn(LD_DIR, "Unable to parse fetched certificates");
1663 /* if we fetched more than one and only some failed, the successful
1664 * ones got flushed to disk so it's safe to call this on them */
1665 connection_dir_download_cert_failed(conn, status_code);
1666 } else {
1667 directory_info_has_arrived(now, 0);
1668 log_info(LD_DIR, "Successfully loaded certificates from fetch.");
1671 if (conn->_base.purpose == DIR_PURPOSE_FETCH_STATUS_VOTE) {
1672 const char *msg;
1673 int st;
1674 log_info(LD_DIR,"Got votes (size %d) from server %s:%d",
1675 (int)body_len, conn->_base.address, conn->_base.port);
1676 if (status_code != 200) {
1677 log_warn(LD_DIR,
1678 "Received http status code %d (%s) from server "
1679 "'%s:%d' while fetching \"/tor/status-vote/next/%s.z\".",
1680 status_code, escaped(reason), conn->_base.address,
1681 conn->_base.port, conn->requested_resource);
1682 tor_free(body); tor_free(headers); tor_free(reason);
1683 return -1;
1685 dirvote_add_vote(body, &msg, &st);
1686 if (st > 299) {
1687 log_warn(LD_DIR, "Error adding retrieved vote: %s", msg);
1688 } else {
1689 log_info(LD_DIR, "Added vote(s) successfully [msg: %s]", msg);
1692 if (conn->_base.purpose == DIR_PURPOSE_FETCH_DETACHED_SIGNATURES) {
1693 const char *msg = NULL;
1694 log_info(LD_DIR,"Got detached signatures (size %d) from server %s:%d",
1695 (int)body_len, conn->_base.address, conn->_base.port);
1696 if (status_code != 200) {
1697 log_warn(LD_DIR,
1698 "Received http status code %d (%s) from server '%s:%d' while fetching "
1699 "\"/tor/status-vote/next/consensus-signatures.z\".",
1700 status_code, escaped(reason), conn->_base.address,
1701 conn->_base.port);
1702 tor_free(body); tor_free(headers); tor_free(reason);
1703 return -1;
1705 if (dirvote_add_signatures(body, conn->_base.address, &msg)<0) {
1706 log_warn(LD_DIR, "Problem adding detached signatures from %s:%d: %s",
1707 conn->_base.address, conn->_base.port, msg?msg:"???");
1711 if (conn->_base.purpose == DIR_PURPOSE_FETCH_SERVERDESC ||
1712 conn->_base.purpose == DIR_PURPOSE_FETCH_EXTRAINFO) {
1713 int was_ei = conn->_base.purpose == DIR_PURPOSE_FETCH_EXTRAINFO;
1714 smartlist_t *which = NULL;
1715 int n_asked_for = 0;
1716 int descriptor_digests = conn->requested_resource &&
1717 !strcmpstart(conn->requested_resource,"d/");
1718 log_info(LD_DIR,"Received %s (size %d) from server '%s:%d'",
1719 was_ei ? "extra server info" : "server info",
1720 (int)body_len, conn->_base.address, conn->_base.port);
1721 if (conn->requested_resource &&
1722 (!strcmpstart(conn->requested_resource,"d/") ||
1723 !strcmpstart(conn->requested_resource,"fp/"))) {
1724 which = smartlist_create();
1725 dir_split_resource_into_fingerprints(conn->requested_resource +
1726 (descriptor_digests ? 2 : 3),
1727 which, NULL, 0);
1728 n_asked_for = smartlist_len(which);
1730 if (status_code != 200) {
1731 int dir_okay = status_code == 404 ||
1732 (status_code == 400 && !strcmp(reason, "Servers unavailable."));
1733 /* 404 means that it didn't have them; no big deal.
1734 * Older (pre-0.1.1.8) servers said 400 Servers unavailable instead. */
1735 log_fn(dir_okay ? LOG_INFO : LOG_WARN, LD_DIR,
1736 "Received http status code %d (%s) from server '%s:%d' "
1737 "while fetching \"/tor/server/%s\". I'll try again soon.",
1738 status_code, escaped(reason), conn->_base.address,
1739 conn->_base.port, conn->requested_resource);
1740 if (!which) {
1741 connection_dir_download_routerdesc_failed(conn);
1742 } else {
1743 dir_routerdesc_download_failed(which, status_code,
1744 conn->router_purpose,
1745 was_ei, descriptor_digests);
1746 SMARTLIST_FOREACH(which, char *, cp, tor_free(cp));
1747 smartlist_free(which);
1749 tor_free(body); tor_free(headers); tor_free(reason);
1750 return dir_okay ? 0 : -1;
1752 /* Learn the routers, assuming we requested by fingerprint or "all"
1753 * or "authority".
1755 * We use "authority" to fetch our own descriptor for
1756 * testing, and to fetch bridge descriptors for bootstrapping. Ignore
1757 * the output of "authority" requests unless we are using bridges,
1758 * since otherwise they'll be the response from reachability tests,
1759 * and we don't really want to add that to our routerlist. */
1760 if (which || (conn->requested_resource &&
1761 (!strcmpstart(conn->requested_resource, "all") ||
1762 (!strcmpstart(conn->requested_resource, "authority") &&
1763 get_options()->UseBridges)))) {
1764 /* as we learn from them, we remove them from 'which' */
1765 if (was_ei) {
1766 router_load_extrainfo_from_string(body, NULL, SAVED_NOWHERE, which,
1767 descriptor_digests);
1768 } else {
1769 //router_load_routers_from_string(body, NULL, SAVED_NOWHERE, which,
1770 // descriptor_digests, conn->router_purpose);
1771 if (load_downloaded_routers(body, which, descriptor_digests,
1772 conn->router_purpose,
1773 conn->_base.address))
1774 directory_info_has_arrived(now, 0);
1777 if (which) { /* mark remaining ones as failed */
1778 log_info(LD_DIR, "Received %d/%d %s requested from %s:%d",
1779 n_asked_for-smartlist_len(which), n_asked_for,
1780 was_ei ? "extra-info documents" : "router descriptors",
1781 conn->_base.address, (int)conn->_base.port);
1782 if (smartlist_len(which)) {
1783 dir_routerdesc_download_failed(which, status_code,
1784 conn->router_purpose,
1785 was_ei, descriptor_digests);
1787 SMARTLIST_FOREACH(which, char *, cp, tor_free(cp));
1788 smartlist_free(which);
1790 if (directory_conn_is_self_reachability_test(conn))
1791 router_dirport_found_reachable();
1794 if (conn->_base.purpose == DIR_PURPOSE_UPLOAD_DIR) {
1795 switch (status_code) {
1796 case 200: {
1797 trusted_dir_server_t *ds =
1798 router_get_trusteddirserver_by_digest(conn->identity_digest);
1799 char *rejected_hdr = http_get_header(headers,
1800 "X-Descriptor-Not-New: ");
1801 int rejected = 0;
1802 if (rejected_hdr) {
1803 if (!strcmp(rejected_hdr, "Yes")) {
1804 log_info(LD_GENERAL,
1805 "Authority '%s' declined our descriptor (not new)",
1806 ds->nickname);
1807 /* XXXX use this information; be sure to upload next one
1808 * sooner. -NM */
1809 /* XXXX021 On further thought, the task above implies that we're
1810 * basing our regenerate-descriptor time on when we uploaded the
1811 * last descriptor, not on the published time of the last
1812 * descriptor. If those are different, that's a bad thing to
1813 * do. -NM */
1814 rejected = 1;
1816 tor_free(rejected_hdr);
1818 log_info(LD_GENERAL,"eof (status 200) after uploading server "
1819 "descriptor: finished.");
1820 control_event_server_status(
1821 LOG_NOTICE, "ACCEPTED_SERVER_DESCRIPTOR DIRAUTH=%s:%d",
1822 conn->_base.address, conn->_base.port);
1824 ds->has_accepted_serverdesc = 1;
1825 if (directories_have_accepted_server_descriptor())
1826 control_event_server_status(LOG_NOTICE, "GOOD_SERVER_DESCRIPTOR");
1828 break;
1829 case 400:
1830 log_warn(LD_GENERAL,"http status 400 (%s) response from "
1831 "dirserver '%s:%d'. Please correct.",
1832 escaped(reason), conn->_base.address, conn->_base.port);
1833 control_event_server_status(LOG_WARN,
1834 "BAD_SERVER_DESCRIPTOR DIRAUTH=%s:%d REASON=\"%s\"",
1835 conn->_base.address, conn->_base.port, escaped(reason));
1836 break;
1837 default:
1838 log_warn(LD_GENERAL,
1839 "http status %d (%s) reason unexpected while uploading "
1840 "descriptor to server '%s:%d').",
1841 status_code, escaped(reason), conn->_base.address,
1842 conn->_base.port);
1843 break;
1845 /* return 0 in all cases, since we don't want to mark any
1846 * dirservers down just because they don't like us. */
1849 if (conn->_base.purpose == DIR_PURPOSE_UPLOAD_VOTE) {
1850 switch (status_code) {
1851 case 200: {
1852 log_notice(LD_DIR,"Uploaded a vote to dirserver %s:%d",
1853 conn->_base.address, conn->_base.port);
1855 break;
1856 case 400:
1857 log_warn(LD_DIR,"http status 400 (%s) response after uploading "
1858 "vote to dirserver '%s:%d'. Please correct.",
1859 escaped(reason), conn->_base.address, conn->_base.port);
1860 break;
1861 default:
1862 log_warn(LD_GENERAL,
1863 "http status %d (%s) reason unexpected while uploading "
1864 "vote to server '%s:%d').",
1865 status_code, escaped(reason), conn->_base.address,
1866 conn->_base.port);
1867 break;
1869 /* return 0 in all cases, since we don't want to mark any
1870 * dirservers down just because they don't like us. */
1873 if (conn->_base.purpose == DIR_PURPOSE_UPLOAD_SIGNATURES) {
1874 switch (status_code) {
1875 case 200: {
1876 log_notice(LD_DIR,"Uploaded signature(s) to dirserver %s:%d",
1877 conn->_base.address, conn->_base.port);
1879 break;
1880 case 400:
1881 log_warn(LD_DIR,"http status 400 (%s) response after uploading "
1882 "signatures to dirserver '%s:%d'. Please correct.",
1883 escaped(reason), conn->_base.address, conn->_base.port);
1884 break;
1885 default:
1886 log_warn(LD_GENERAL,
1887 "http status %d (%s) reason unexpected while uploading "
1888 "signatures to server '%s:%d').",
1889 status_code, escaped(reason), conn->_base.address,
1890 conn->_base.port);
1891 break;
1893 /* return 0 in all cases, since we don't want to mark any
1894 * dirservers down just because they don't like us. */
1897 if (conn->_base.purpose == DIR_PURPOSE_FETCH_RENDDESC) {
1898 tor_assert(conn->rend_data);
1899 log_info(LD_REND,"Received rendezvous descriptor (size %d, status %d "
1900 "(%s))",
1901 (int)body_len, status_code, escaped(reason));
1902 switch (status_code) {
1903 case 200:
1904 if (rend_cache_store(body, body_len, 0) < -1) {
1905 log_warn(LD_REND,"Failed to parse rendezvous descriptor.");
1906 /* Any pending rendezvous attempts will notice when
1907 * connection_about_to_close_connection()
1908 * cleans this dir conn up. */
1909 /* We could retry. But since v0 descriptors are going out of
1910 * style, it isn't worth the hassle. We'll do better in v2. */
1911 } else {
1912 /* Success, or at least there's a v2 descriptor already
1913 * present. Notify pending connections about this. */
1914 conn->_base.purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC;
1915 rend_client_desc_trynow(conn->rend_data->onion_address);
1917 break;
1918 case 404:
1919 /* Not there. Pending connections will be notified when
1920 * connection_about_to_close_connection() cleans this conn up. */
1921 break;
1922 case 400:
1923 log_warn(LD_REND,
1924 "http status 400 (%s). Dirserver didn't like our "
1925 "rendezvous query?", escaped(reason));
1926 break;
1927 default:
1928 log_warn(LD_REND,"http status %d (%s) response unexpected while "
1929 "fetching hidden service descriptor (server '%s:%d').",
1930 status_code, escaped(reason), conn->_base.address,
1931 conn->_base.port);
1932 break;
1936 if (conn->_base.purpose == DIR_PURPOSE_FETCH_RENDDESC_V2) {
1937 tor_assert(conn->rend_data);
1938 log_info(LD_REND,"Received rendezvous descriptor (size %d, status %d "
1939 "(%s))",
1940 (int)body_len, status_code, escaped(reason));
1941 switch (status_code) {
1942 case 200:
1943 switch (rend_cache_store_v2_desc_as_client(body, conn->rend_data)) {
1944 case -2:
1945 log_warn(LD_REND,"Fetching v2 rendezvous descriptor failed. "
1946 "Retrying at another directory.");
1947 /* We'll retry when connection_about_to_close_connection()
1948 * cleans this dir conn up. */
1949 break;
1950 case -1:
1951 /* We already have a v0 descriptor here. Ignoring this one
1952 * and _not_ performing another request. */
1953 log_info(LD_REND, "Successfully fetched v2 rendezvous "
1954 "descriptor, but we already have a v0 descriptor.");
1955 conn->_base.purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC;
1956 break;
1957 default:
1958 /* success. notify pending connections about this. */
1959 log_info(LD_REND, "Successfully fetched v2 rendezvous "
1960 "descriptor.");
1961 conn->_base.purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC;
1962 rend_client_desc_trynow(conn->rend_data->onion_address);
1963 break;
1965 break;
1966 case 404:
1967 /* Not there. We'll retry when
1968 * connection_about_to_close_connection() cleans this conn up. */
1969 log_info(LD_REND,"Fetching v2 rendezvous descriptor failed: "
1970 "Retrying at another directory.");
1971 break;
1972 case 400:
1973 log_warn(LD_REND, "Fetching v2 rendezvous descriptor failed: "
1974 "http status 400 (%s). Dirserver didn't like our "
1975 "v2 rendezvous query? Retrying at another directory.",
1976 escaped(reason));
1977 break;
1978 default:
1979 log_warn(LD_REND, "Fetching v2 rendezvous descriptor failed: "
1980 "http status %d (%s) response unexpected while "
1981 "fetching v2 hidden service descriptor (server '%s:%d'). "
1982 "Retrying at another directory.",
1983 status_code, escaped(reason), conn->_base.address,
1984 conn->_base.port);
1985 break;
1989 if (conn->_base.purpose == DIR_PURPOSE_UPLOAD_RENDDESC ||
1990 conn->_base.purpose == DIR_PURPOSE_UPLOAD_RENDDESC_V2) {
1991 log_info(LD_REND,"Uploaded rendezvous descriptor (status %d "
1992 "(%s))",
1993 status_code, escaped(reason));
1994 switch (status_code) {
1995 case 200:
1996 log_info(LD_REND,
1997 "Uploading rendezvous descriptor: finished with status "
1998 "200 (%s)", escaped(reason));
1999 break;
2000 case 400:
2001 log_warn(LD_REND,"http status 400 (%s) response from dirserver "
2002 "'%s:%d'. Malformed rendezvous descriptor?",
2003 escaped(reason), conn->_base.address, conn->_base.port);
2004 break;
2005 default:
2006 log_warn(LD_REND,"http status %d (%s) response unexpected (server "
2007 "'%s:%d').",
2008 status_code, escaped(reason), conn->_base.address,
2009 conn->_base.port);
2010 break;
2013 note_client_request(conn->_base.purpose, was_compressed, orig_len);
2014 tor_free(body); tor_free(headers); tor_free(reason);
2015 return 0;
2018 /** Called when a directory connection reaches EOF. */
2020 connection_dir_reached_eof(dir_connection_t *conn)
2022 int retval;
2023 if (conn->_base.state != DIR_CONN_STATE_CLIENT_READING) {
2024 log_info(LD_HTTP,"conn reached eof, not reading. [state=%d] Closing.",
2025 conn->_base.state);
2026 connection_close_immediate(TO_CONN(conn)); /* error: give up on flushing */
2027 connection_mark_for_close(TO_CONN(conn));
2028 return -1;
2031 retval = connection_dir_client_reached_eof(conn);
2032 if (retval == 0) /* success */
2033 conn->_base.state = DIR_CONN_STATE_CLIENT_FINISHED;
2034 connection_mark_for_close(TO_CONN(conn));
2035 return retval;
2038 /** If any directory object is arriving, and it's over 10MB large, we're
2039 * getting DoS'd. (As of 0.1.2.x, raw directories are about 1MB, and we never
2040 * ask for more than 96 router descriptors at a time.)
2042 #define MAX_DIRECTORY_OBJECT_SIZE (10*(1<<20))
2044 /** Read handler for directory connections. (That's connections <em>to</em>
2045 * directory servers and connections <em>at</em> directory servers.)
2048 connection_dir_process_inbuf(dir_connection_t *conn)
2050 tor_assert(conn);
2051 tor_assert(conn->_base.type == CONN_TYPE_DIR);
2053 /* Directory clients write, then read data until they receive EOF;
2054 * directory servers read data until they get an HTTP command, then
2055 * write their response (when it's finished flushing, they mark for
2056 * close).
2059 /* If we're on the dirserver side, look for a command. */
2060 if (conn->_base.state == DIR_CONN_STATE_SERVER_COMMAND_WAIT) {
2061 if (directory_handle_command(conn) < 0) {
2062 connection_mark_for_close(TO_CONN(conn));
2063 return -1;
2065 return 0;
2068 if (buf_datalen(conn->_base.inbuf) > MAX_DIRECTORY_OBJECT_SIZE) {
2069 log_warn(LD_HTTP, "Too much data received from directory connection: "
2070 "denial of service attempt, or you need to upgrade?");
2071 connection_mark_for_close(TO_CONN(conn));
2072 return -1;
2075 if (!conn->_base.inbuf_reached_eof)
2076 log_debug(LD_HTTP,"Got data, not eof. Leaving on inbuf.");
2077 return 0;
2080 /** Create an http response for the client <b>conn</b> out of
2081 * <b>status</b> and <b>reason_phrase</b>. Write it to <b>conn</b>.
2083 static void
2084 write_http_status_line(dir_connection_t *conn, int status,
2085 const char *reason_phrase)
2087 char buf[256];
2088 if (tor_snprintf(buf, sizeof(buf), "HTTP/1.0 %d %s\r\n\r\n",
2089 status, reason_phrase ? reason_phrase : "OK") < 0) {
2090 log_warn(LD_BUG,"status line too long.");
2091 return;
2093 connection_write_to_buf(buf, strlen(buf), TO_CONN(conn));
2096 /** Write the header for an HTTP/1.0 response onto <b>conn</b>-\>outbuf,
2097 * with <b>type</b> as the Content-Type.
2099 * If <b>length</b> is nonnegative, it is the Content-Length.
2100 * If <b>encoding</b> is provided, it is the Content-Encoding.
2101 * If <b>cache_lifetime</b> is greater than 0, the content may be cached for
2102 * up to cache_lifetime seconds. Otherwise, the content may not be cached. */
2103 static void
2104 write_http_response_header_impl(dir_connection_t *conn, ssize_t length,
2105 const char *type, const char *encoding,
2106 const char *extra_headers,
2107 long cache_lifetime)
2109 char date[RFC1123_TIME_LEN+1];
2110 char tmp[1024];
2111 char *cp;
2112 time_t now = time(NULL);
2114 tor_assert(conn);
2116 format_rfc1123_time(date, now);
2117 cp = tmp;
2118 tor_snprintf(cp, sizeof(tmp),
2119 "HTTP/1.0 200 OK\r\nDate: %s\r\n",
2120 date);
2121 cp += strlen(tmp);
2122 if (type) {
2123 tor_snprintf(cp, sizeof(tmp)-(cp-tmp), "Content-Type: %s\r\n", type);
2124 cp += strlen(cp);
2126 if (!is_local_addr(&conn->_base.addr)) {
2127 /* Don't report the source address for a nearby/private connection.
2128 * Otherwise we tend to mis-report in cases where incoming ports are
2129 * being forwarded to a Tor server running behind the firewall. */
2130 tor_snprintf(cp, sizeof(tmp)-(cp-tmp),
2131 X_ADDRESS_HEADER "%s\r\n", conn->_base.address);
2132 cp += strlen(cp);
2134 if (encoding) {
2135 tor_snprintf(cp, sizeof(tmp)-(cp-tmp),
2136 "Content-Encoding: %s\r\n", encoding);
2137 cp += strlen(cp);
2139 if (length >= 0) {
2140 tor_snprintf(cp, sizeof(tmp)-(cp-tmp),
2141 "Content-Length: %ld\r\n", (long)length);
2142 cp += strlen(cp);
2144 if (cache_lifetime > 0) {
2145 char expbuf[RFC1123_TIME_LEN+1];
2146 format_rfc1123_time(expbuf, now + cache_lifetime);
2147 /* We could say 'Cache-control: max-age=%d' here if we start doing
2148 * http/1.1 */
2149 tor_snprintf(cp, sizeof(tmp)-(cp-tmp),
2150 "Expires: %s\r\n", expbuf);
2151 cp += strlen(cp);
2152 } else if (cache_lifetime == 0) {
2153 /* We could say 'Cache-control: no-cache' here if we start doing
2154 * http/1.1 */
2155 strlcpy(cp, "Pragma: no-cache\r\n", sizeof(tmp)-(cp-tmp));
2156 cp += strlen(cp);
2158 if (extra_headers) {
2159 strlcpy(cp, extra_headers, sizeof(tmp)-(cp-tmp));
2160 cp += strlen(cp);
2162 if (sizeof(tmp)-(cp-tmp) > 3)
2163 memcpy(cp, "\r\n", 3);
2164 else
2165 tor_assert(0);
2166 connection_write_to_buf(tmp, strlen(tmp), TO_CONN(conn));
2169 /** As write_http_response_header_impl, but sets encoding and content-typed
2170 * based on whether the response will be <b>compressed</b> or not. */
2171 static void
2172 write_http_response_header(dir_connection_t *conn, ssize_t length,
2173 int compressed, long cache_lifetime)
2175 write_http_response_header_impl(conn, length,
2176 compressed?"application/octet-stream":"text/plain",
2177 compressed?"deflate":"identity",
2178 NULL,
2179 cache_lifetime);
2182 #ifdef INSTRUMENT_DOWNLOADS
2183 typedef struct request_t {
2184 uint64_t bytes; /**< How many bytes have we transferred? */
2185 uint64_t count; /**< How many requests have we made? */
2186 } request_t;
2188 /** Map used to keep track of how much data we've up/downloaded in what kind
2189 * of request. Maps from request type to pointer to request_t. */
2190 static strmap_t *request_map = NULL;
2192 /** Record that a client request of <b>purpose</b> was made, and that
2193 * <b>bytes</b> bytes of possibly <b>compressed</b> data were sent/received.
2194 * Used to keep track of how much we've up/downloaded in what kind of
2195 * request. */
2196 static void
2197 note_client_request(int purpose, int compressed, size_t bytes)
2199 char *key;
2200 const char *kind = NULL;
2201 switch (purpose) {
2202 case DIR_PURPOSE_FETCH_V2_NETWORKSTATUS: kind = "dl/status"; break;
2203 case DIR_PURPOSE_FETCH_CONSENSUS: kind = "dl/consensus"; break;
2204 case DIR_PURPOSE_FETCH_CERTIFICATE: kind = "dl/cert"; break;
2205 case DIR_PURPOSE_FETCH_STATUS_VOTE: kind = "dl/vote"; break;
2206 case DIR_PURPOSE_FETCH_DETACHED_SIGNATURES: kind = "dl/detached_sig";
2207 break;
2208 case DIR_PURPOSE_FETCH_SERVERDESC: kind = "dl/server"; break;
2209 case DIR_PURPOSE_FETCH_EXTRAINFO: kind = "dl/extra"; break;
2210 case DIR_PURPOSE_UPLOAD_DIR: kind = "dl/ul-dir"; break;
2211 case DIR_PURPOSE_UPLOAD_VOTE: kind = "dl/ul-vote"; break;
2212 case DIR_PURPOSE_UPLOAD_SIGNATURES: kind = "dl/ul-sig"; break;
2213 case DIR_PURPOSE_FETCH_RENDDESC: kind = "dl/rend"; break;
2214 case DIR_PURPOSE_FETCH_RENDDESC_V2: kind = "dl/rend2"; break;
2215 case DIR_PURPOSE_UPLOAD_RENDDESC: kind = "dl/ul-rend"; break;
2216 case DIR_PURPOSE_UPLOAD_RENDDESC_V2: kind = "dl/ul-rend2"; break;
2218 if (kind) {
2219 key = tor_malloc(256);
2220 tor_snprintf(key, 256, "%s%s", kind, compressed?".z":"");
2221 } else {
2222 key = tor_malloc(256);
2223 tor_snprintf(key, 256, "unknown purpose (%d)%s",
2224 purpose, compressed?".z":"");
2226 note_request(key, bytes);
2227 tor_free(key);
2230 /** Helper: initialize the request map to instrument downloads. */
2231 static void
2232 ensure_request_map_initialized(void)
2234 if (!request_map)
2235 request_map = strmap_new();
2238 /** Called when we just transmitted or received <b>bytes</b> worth of data
2239 * because of a request of type <b>key</b> (an arbitrary identifier): adds
2240 * <b>bytes</b> to the total associated with key. */
2241 void
2242 note_request(const char *key, size_t bytes)
2244 request_t *r;
2245 ensure_request_map_initialized();
2247 r = strmap_get(request_map, key);
2248 if (!r) {
2249 r = tor_malloc_zero(sizeof(request_t));
2250 strmap_set(request_map, key, r);
2252 r->bytes += bytes;
2253 r->count++;
2256 /** Return a newly allocated string holding a summary of bytes used per
2257 * request type. */
2258 char *
2259 directory_dump_request_log(void)
2261 smartlist_t *lines;
2262 char tmp[256];
2263 char *result;
2264 strmap_iter_t *iter;
2266 ensure_request_map_initialized();
2268 lines = smartlist_create();
2270 for (iter = strmap_iter_init(request_map);
2271 !strmap_iter_done(iter);
2272 iter = strmap_iter_next(request_map, iter)) {
2273 const char *key;
2274 void *val;
2275 request_t *r;
2276 strmap_iter_get(iter, &key, &val);
2277 r = val;
2278 tor_snprintf(tmp, sizeof(tmp), "%s "U64_FORMAT" "U64_FORMAT"\n",
2279 key, U64_PRINTF_ARG(r->bytes), U64_PRINTF_ARG(r->count));
2280 smartlist_add(lines, tor_strdup(tmp));
2282 smartlist_sort_strings(lines);
2283 result = smartlist_join_strings(lines, "", 0, NULL);
2284 SMARTLIST_FOREACH(lines, char *, cp, tor_free(cp));
2285 smartlist_free(lines);
2286 return result;
2288 #else
2289 static void
2290 note_client_request(int purpose, int compressed, size_t bytes)
2292 (void)purpose;
2293 (void)compressed;
2294 (void)bytes;
2297 void
2298 note_request(const char *key, size_t bytes)
2300 (void)key;
2301 (void)bytes;
2304 char *
2305 directory_dump_request_log(void)
2307 return tor_strdup("Not supported.");
2309 #endif
2311 /** Decide whether a client would accept the consensus we have.
2313 * Clients can say they only want a consensus if it's signed by more
2314 * than half the authorities in a list. They pass this list in
2315 * the url as "...consensus/<b>fpr</b>+<b>fpr</b>+<b>fpr</b>".
2317 * <b>fpr</b> may be an abbreviated fingerprint, i.e. only a left substring
2318 * of the full authority identity digest. (Only strings of even length,
2319 * i.e. encodings of full bytes, are handled correctly. In the case
2320 * of an odd number of hex digits the last one is silently ignored.)
2322 * Returns 1 if more than half of the requested authorities signed the
2323 * consensus, 0 otherwise.
2326 client_likes_consensus(networkstatus_t *v, const char *want_url)
2328 smartlist_t *want_authorities = smartlist_create();
2329 int need_at_least;
2330 int have = 0;
2332 dir_split_resource_into_fingerprints(want_url, want_authorities, NULL, 0);
2333 need_at_least = smartlist_len(want_authorities)/2+1;
2334 SMARTLIST_FOREACH_BEGIN(want_authorities, const char *, d) {
2335 char want_digest[DIGEST_LEN];
2336 size_t want_len = strlen(d)/2;
2337 if (want_len > DIGEST_LEN)
2338 want_len = DIGEST_LEN;
2340 if (base16_decode(want_digest, DIGEST_LEN, d, want_len*2) < 0) {
2341 log_fn(LOG_PROTOCOL_WARN, LD_DIR,
2342 "Failed to decode requested authority digest %s.", d);
2343 continue;
2346 SMARTLIST_FOREACH_BEGIN(v->voters, networkstatus_voter_info_t *, vi) {
2347 if (smartlist_len(vi->sigs) &&
2348 !memcmp(vi->identity_digest, want_digest, want_len)) {
2349 have++;
2350 break;
2352 } SMARTLIST_FOREACH_END(vi);
2354 /* early exit, if we already have enough */
2355 if (have >= need_at_least)
2356 break;
2357 } SMARTLIST_FOREACH_END(d);
2359 SMARTLIST_FOREACH(want_authorities, char *, d, tor_free(d));
2360 smartlist_free(want_authorities);
2361 return (have >= need_at_least);
2364 /** Helper function: called when a dirserver gets a complete HTTP GET
2365 * request. Look for a request for a directory or for a rendezvous
2366 * service descriptor. On finding one, write a response into
2367 * conn-\>outbuf. If the request is unrecognized, send a 400.
2368 * Always return 0. */
2369 static int
2370 directory_handle_command_get(dir_connection_t *conn, const char *headers,
2371 const char *body, size_t body_len)
2373 size_t dlen;
2374 char *url, *url_mem, *header;
2375 or_options_t *options = get_options();
2376 time_t if_modified_since = 0;
2377 int compressed;
2378 size_t url_len;
2380 /* We ignore the body of a GET request. */
2381 (void)body;
2382 (void)body_len;
2384 log_debug(LD_DIRSERV,"Received GET command.");
2386 conn->_base.state = DIR_CONN_STATE_SERVER_WRITING;
2388 if (parse_http_url(headers, &url) < 0) {
2389 write_http_status_line(conn, 400, "Bad request");
2390 return 0;
2392 if ((header = http_get_header(headers, "If-Modified-Since: "))) {
2393 struct tm tm;
2394 if (parse_http_time(header, &tm) == 0) {
2395 if_modified_since = tor_timegm(&tm);
2397 /* The correct behavior on a malformed If-Modified-Since header is to
2398 * act as if no If-Modified-Since header had been given. */
2399 tor_free(header);
2401 log_debug(LD_DIRSERV,"rewritten url as '%s'.", url);
2403 url_mem = url;
2404 url_len = strlen(url);
2405 compressed = url_len > 2 && !strcmp(url+url_len-2, ".z");
2406 if (compressed) {
2407 url[url_len-2] = '\0';
2408 url_len -= 2;
2411 if (!strcmp(url,"/tor/")) {
2412 const char *frontpage = get_dirportfrontpage();
2414 if (frontpage) {
2415 dlen = strlen(frontpage);
2416 /* Let's return a disclaimer page (users shouldn't use V1 anymore,
2417 and caches don't fetch '/', so this is safe). */
2419 /* [We don't check for write_bucket_low here, since we want to serve
2420 * this page no matter what.] */
2421 note_request(url, dlen);
2422 write_http_response_header_impl(conn, dlen, "text/html", "identity",
2423 NULL, DIRPORTFRONTPAGE_CACHE_LIFETIME);
2424 connection_write_to_buf(frontpage, dlen, TO_CONN(conn));
2425 goto done;
2427 /* if no disclaimer file, fall through and continue */
2430 if (!strcmp(url,"/tor/") || !strcmp(url,"/tor/dir")) { /* v1 dir fetch */
2431 cached_dir_t *d = dirserv_get_directory();
2433 if (!d) {
2434 log_info(LD_DIRSERV,"Client asked for the mirrored directory, but we "
2435 "don't have a good one yet. Sending 503 Dir not available.");
2436 write_http_status_line(conn, 503, "Directory unavailable");
2437 goto done;
2439 if (d->published < if_modified_since) {
2440 write_http_status_line(conn, 304, "Not modified");
2441 goto done;
2444 dlen = compressed ? d->dir_z_len : d->dir_len;
2446 if (global_write_bucket_low(TO_CONN(conn), dlen, 1)) {
2447 log_debug(LD_DIRSERV,
2448 "Client asked for the mirrored directory, but we've been "
2449 "writing too many bytes lately. Sending 503 Dir busy.");
2450 write_http_status_line(conn, 503, "Directory busy, try again later");
2451 goto done;
2454 note_request(url, dlen);
2456 log_debug(LD_DIRSERV,"Dumping %sdirectory to client.",
2457 compressed?"compressed ":"");
2458 write_http_response_header(conn, dlen, compressed,
2459 FULL_DIR_CACHE_LIFETIME);
2460 conn->cached_dir = d;
2461 conn->cached_dir_offset = 0;
2462 if (!compressed)
2463 conn->zlib_state = tor_zlib_new(0, ZLIB_METHOD);
2464 ++d->refcnt;
2466 /* Prime the connection with some data. */
2467 conn->dir_spool_src = DIR_SPOOL_CACHED_DIR;
2468 connection_dirserv_flushed_some(conn);
2469 goto done;
2472 if (!strcmp(url,"/tor/running-routers")) { /* running-routers fetch */
2473 cached_dir_t *d = dirserv_get_runningrouters();
2474 if (!d) {
2475 write_http_status_line(conn, 503, "Directory unavailable");
2476 goto done;
2478 if (d->published < if_modified_since) {
2479 write_http_status_line(conn, 304, "Not modified");
2480 goto done;
2482 dlen = compressed ? d->dir_z_len : d->dir_len;
2484 if (global_write_bucket_low(TO_CONN(conn), dlen, 1)) {
2485 log_info(LD_DIRSERV,
2486 "Client asked for running-routers, but we've been "
2487 "writing too many bytes lately. Sending 503 Dir busy.");
2488 write_http_status_line(conn, 503, "Directory busy, try again later");
2489 goto done;
2491 note_request(url, dlen);
2492 write_http_response_header(conn, dlen, compressed,
2493 RUNNINGROUTERS_CACHE_LIFETIME);
2494 connection_write_to_buf(compressed ? d->dir_z : d->dir, dlen,
2495 TO_CONN(conn));
2496 goto done;
2499 if (!strcmpstart(url,"/tor/status/")
2500 || !strcmpstart(url, "/tor/status-vote/current/consensus")) {
2501 /* v2 or v3 network status fetch. */
2502 smartlist_t *dir_fps = smartlist_create();
2503 int is_v3 = !strcmpstart(url, "/tor/status-vote");
2504 geoip_client_action_t act =
2505 is_v3 ? GEOIP_CLIENT_NETWORKSTATUS : GEOIP_CLIENT_NETWORKSTATUS_V2;
2506 const char *request_type = NULL;
2507 const char *key = url + strlen("/tor/status/");
2508 long lifetime = NETWORKSTATUS_CACHE_LIFETIME;
2510 if (!is_v3) {
2511 dirserv_get_networkstatus_v2_fingerprints(dir_fps, key);
2512 if (!strcmpstart(key, "fp/"))
2513 request_type = compressed?"/tor/status/fp.z":"/tor/status/fp";
2514 else if (!strcmpstart(key, "authority"))
2515 request_type = compressed?"/tor/status/authority.z":
2516 "/tor/status/authority";
2517 else if (!strcmpstart(key, "all"))
2518 request_type = compressed?"/tor/status/all.z":"/tor/status/all";
2519 else
2520 request_type = "/tor/status/?";
2521 } else {
2522 networkstatus_t *v = networkstatus_get_latest_consensus();
2523 time_t now = time(NULL);
2524 const char *want_fps = NULL;
2525 char *flavor = NULL;
2526 #define CONSENSUS_URL_PREFIX "/tor/status-vote/current/consensus/"
2527 #define CONSENSUS_FLAVORED_PREFIX "/tor/status-vote/current/consensus-"
2528 /* figure out the flavor if any, and who we wanted to sign the thing */
2529 if (!strcmpstart(url, CONSENSUS_FLAVORED_PREFIX)) {
2530 const char *f, *cp;
2531 f = url + strlen(CONSENSUS_FLAVORED_PREFIX);
2532 cp = strchr(f, '/');
2533 if (cp) {
2534 want_fps = cp+1;
2535 flavor = tor_strndup(f, cp-f);
2536 } else {
2537 flavor = tor_strdup(f);
2539 } else {
2540 if (!strcmpstart(url, CONSENSUS_URL_PREFIX))
2541 want_fps = url+strlen(CONSENSUS_URL_PREFIX);
2544 /* XXXX MICRODESC NM NM should check document of correct flavor */
2545 if (v && want_fps &&
2546 !client_likes_consensus(v, want_fps)) {
2547 write_http_status_line(conn, 404, "Consensus not signed by sufficient "
2548 "number of requested authorities");
2549 smartlist_free(dir_fps);
2550 geoip_note_ns_response(act, GEOIP_REJECT_NOT_ENOUGH_SIGS);
2551 tor_free(flavor);
2552 goto done;
2556 char *fp = tor_malloc_zero(DIGEST_LEN);
2557 if (flavor)
2558 strlcpy(fp, flavor, DIGEST_LEN);
2559 tor_free(flavor);
2560 smartlist_add(dir_fps, fp);
2562 request_type = compressed?"v3.z":"v3";
2563 lifetime = (v && v->fresh_until > now) ? v->fresh_until - now : 0;
2566 if (!smartlist_len(dir_fps)) { /* we failed to create/cache cp */
2567 write_http_status_line(conn, 503, "Network status object unavailable");
2568 smartlist_free(dir_fps);
2569 geoip_note_ns_response(act, GEOIP_REJECT_UNAVAILABLE);
2570 goto done;
2573 if (!dirserv_remove_old_statuses(dir_fps, if_modified_since)) {
2574 write_http_status_line(conn, 404, "Not found");
2575 SMARTLIST_FOREACH(dir_fps, char *, cp, tor_free(cp));
2576 smartlist_free(dir_fps);
2577 geoip_note_ns_response(act, GEOIP_REJECT_NOT_FOUND);
2578 goto done;
2579 } else if (!smartlist_len(dir_fps)) {
2580 write_http_status_line(conn, 304, "Not modified");
2581 SMARTLIST_FOREACH(dir_fps, char *, cp, tor_free(cp));
2582 smartlist_free(dir_fps);
2583 geoip_note_ns_response(act, GEOIP_REJECT_NOT_MODIFIED);
2584 goto done;
2587 dlen = dirserv_estimate_data_size(dir_fps, 0, compressed);
2588 if (global_write_bucket_low(TO_CONN(conn), dlen, 2)) {
2589 log_debug(LD_DIRSERV,
2590 "Client asked for network status lists, but we've been "
2591 "writing too many bytes lately. Sending 503 Dir busy.");
2592 write_http_status_line(conn, 503, "Directory busy, try again later");
2593 SMARTLIST_FOREACH(dir_fps, char *, fp, tor_free(fp));
2594 smartlist_free(dir_fps);
2595 geoip_note_ns_response(act, GEOIP_REJECT_BUSY);
2596 goto done;
2600 struct in_addr in;
2601 if (tor_inet_aton((TO_CONN(conn))->address, &in)) {
2602 geoip_note_client_seen(act, ntohl(in.s_addr), time(NULL));
2603 geoip_note_ns_response(act, GEOIP_SUCCESS);
2604 /* Note that a request for a network status has started, so that we
2605 * can measure the download time later on. */
2606 if (TO_CONN(conn)->dirreq_id)
2607 geoip_start_dirreq(TO_CONN(conn)->dirreq_id, dlen, act,
2608 DIRREQ_TUNNELED);
2609 else
2610 geoip_start_dirreq(TO_CONN(conn)->global_identifier, dlen, act,
2611 DIRREQ_DIRECT);
2615 // note_request(request_type,dlen);
2616 (void) request_type;
2617 write_http_response_header(conn, -1, compressed,
2618 smartlist_len(dir_fps) == 1 ? lifetime : 0);
2619 conn->fingerprint_stack = dir_fps;
2620 if (! compressed)
2621 conn->zlib_state = tor_zlib_new(0, ZLIB_METHOD);
2623 /* Prime the connection with some data. */
2624 conn->dir_spool_src = DIR_SPOOL_NETWORKSTATUS;
2625 connection_dirserv_flushed_some(conn);
2626 goto done;
2629 if (!strcmpstart(url,"/tor/status-vote/current/") ||
2630 !strcmpstart(url,"/tor/status-vote/next/")) {
2631 /* XXXX If-modified-since is only implemented for the current
2632 * consensus: that's probably fine, since it's the only vote document
2633 * people fetch much. */
2634 int current;
2635 ssize_t body_len = 0;
2636 ssize_t estimated_len = 0;
2637 smartlist_t *items = smartlist_create();
2638 smartlist_t *dir_items = smartlist_create();
2639 int lifetime = 60; /* XXXX022 should actually use vote intervals. */
2640 url += strlen("/tor/status-vote/");
2641 current = !strcmpstart(url, "current/");
2642 url = strchr(url, '/');
2643 tor_assert(url);
2644 ++url;
2645 if (!strcmp(url, "consensus")) {
2646 const char *item;
2647 tor_assert(!current); /* we handle current consensus specially above,
2648 * since it wants to be spooled. */
2649 if ((item = dirvote_get_pending_consensus(FLAV_NS)))
2650 smartlist_add(items, (char*)item);
2651 } else if (!current && !strcmp(url, "consensus-signatures")) {
2652 /* XXXX the spec says that we should implement
2653 * current/consensus-signatures too. It doesn't seem to be needed,
2654 * though. */
2655 const char *item;
2656 if ((item=dirvote_get_pending_detached_signatures()))
2657 smartlist_add(items, (char*)item);
2658 } else if (!strcmp(url, "authority")) {
2659 const cached_dir_t *d;
2660 int flags = DGV_BY_ID |
2661 (current ? DGV_INCLUDE_PREVIOUS : DGV_INCLUDE_PENDING);
2662 if ((d=dirvote_get_vote(NULL, flags)))
2663 smartlist_add(dir_items, (cached_dir_t*)d);
2664 } else {
2665 const cached_dir_t *d;
2666 smartlist_t *fps = smartlist_create();
2667 int flags;
2668 if (!strcmpstart(url, "d/")) {
2669 url += 2;
2670 flags = DGV_INCLUDE_PENDING | DGV_INCLUDE_PREVIOUS;
2671 } else {
2672 flags = DGV_BY_ID |
2673 (current ? DGV_INCLUDE_PREVIOUS : DGV_INCLUDE_PENDING);
2675 dir_split_resource_into_fingerprints(url, fps, NULL,
2676 DSR_HEX|DSR_SORT_UNIQ);
2677 SMARTLIST_FOREACH(fps, char *, fp, {
2678 if ((d = dirvote_get_vote(fp, flags)))
2679 smartlist_add(dir_items, (cached_dir_t*)d);
2680 tor_free(fp);
2682 smartlist_free(fps);
2684 if (!smartlist_len(dir_items) && !smartlist_len(items)) {
2685 write_http_status_line(conn, 404, "Not found");
2686 goto vote_done;
2688 SMARTLIST_FOREACH(dir_items, cached_dir_t *, d,
2689 body_len += compressed ? d->dir_z_len : d->dir_len);
2690 estimated_len += body_len;
2691 SMARTLIST_FOREACH(items, const char *, item, {
2692 size_t ln = strlen(item);
2693 if (compressed) {
2694 estimated_len += ln/2;
2695 } else {
2696 body_len += ln; estimated_len += ln;
2700 if (global_write_bucket_low(TO_CONN(conn), estimated_len, 2)) {
2701 write_http_status_line(conn, 503, "Directory busy, try again later.");
2702 goto vote_done;
2704 write_http_response_header(conn, body_len ? body_len : -1, compressed,
2705 lifetime);
2707 if (smartlist_len(items)) {
2708 if (compressed) {
2709 conn->zlib_state = tor_zlib_new(1, ZLIB_METHOD);
2710 SMARTLIST_FOREACH(items, const char *, c,
2711 connection_write_to_buf_zlib(c, strlen(c), conn, 0));
2712 connection_write_to_buf_zlib("", 0, conn, 1);
2713 } else {
2714 SMARTLIST_FOREACH(items, const char *, c,
2715 connection_write_to_buf(c, strlen(c), TO_CONN(conn)));
2717 } else {
2718 SMARTLIST_FOREACH(dir_items, cached_dir_t *, d,
2719 connection_write_to_buf(compressed ? d->dir_z : d->dir,
2720 compressed ? d->dir_z_len : d->dir_len,
2721 TO_CONN(conn)));
2723 vote_done:
2724 smartlist_free(items);
2725 smartlist_free(dir_items);
2726 goto done;
2729 if (!strcmpstart(url, "/tor/micro/d/")) {
2730 smartlist_t *fps = smartlist_create();
2732 dir_split_resource_into_fingerprints(url+strlen("/tor/micro/d/"),
2733 fps, NULL,
2734 DSR_DIGEST256|DSR_BASE64|DSR_SORT_UNIQ);
2736 if (!dirserv_have_any_microdesc(fps)) {
2737 write_http_status_line(conn, 404, "Not found");
2738 SMARTLIST_FOREACH(fps, char *, fp, tor_free(fp));
2739 smartlist_free(fps);
2740 goto done;
2742 dlen = dirserv_estimate_microdesc_size(fps, compressed);
2743 if (global_write_bucket_low(TO_CONN(conn), dlen, 2)) {
2744 log_info(LD_DIRSERV,
2745 "Client asked for server descriptors, but we've been "
2746 "writing too many bytes lately. Sending 503 Dir busy.");
2747 write_http_status_line(conn, 503, "Directory busy, try again later");
2748 SMARTLIST_FOREACH(fps, char *, fp, tor_free(fp));
2749 smartlist_free(fps);
2750 goto done;
2753 write_http_response_header(conn, -1, compressed, MICRODESC_CACHE_LIFETIME);
2754 conn->dir_spool_src = DIR_SPOOL_MICRODESC;
2755 conn->fingerprint_stack = fps;
2757 if (compressed)
2758 conn->zlib_state = tor_zlib_new(1, ZLIB_METHOD);
2760 connection_dirserv_flushed_some(conn);
2761 goto done;
2764 if (!strcmpstart(url,"/tor/server/") ||
2765 (!options->BridgeAuthoritativeDir &&
2766 !options->BridgeRelay && !strcmpstart(url,"/tor/extra/"))) {
2767 int res;
2768 const char *msg;
2769 const char *request_type = NULL;
2770 int cache_lifetime = 0;
2771 int is_extra = !strcmpstart(url,"/tor/extra/");
2772 url += is_extra ? strlen("/tor/extra/") : strlen("/tor/server/");
2773 conn->fingerprint_stack = smartlist_create();
2774 res = dirserv_get_routerdesc_fingerprints(conn->fingerprint_stack, url,
2775 &msg,
2776 !connection_dir_is_encrypted(conn),
2777 is_extra);
2779 if (!strcmpstart(url, "fp/")) {
2780 request_type = compressed?"/tor/server/fp.z":"/tor/server/fp";
2781 if (smartlist_len(conn->fingerprint_stack) == 1)
2782 cache_lifetime = ROUTERDESC_CACHE_LIFETIME;
2783 } else if (!strcmpstart(url, "authority")) {
2784 request_type = compressed?"/tor/server/authority.z":
2785 "/tor/server/authority";
2786 cache_lifetime = ROUTERDESC_CACHE_LIFETIME;
2787 } else if (!strcmpstart(url, "all")) {
2788 request_type = compressed?"/tor/server/all.z":"/tor/server/all";
2789 cache_lifetime = FULL_DIR_CACHE_LIFETIME;
2790 } else if (!strcmpstart(url, "d/")) {
2791 request_type = compressed?"/tor/server/d.z":"/tor/server/d";
2792 if (smartlist_len(conn->fingerprint_stack) == 1)
2793 cache_lifetime = ROUTERDESC_BY_DIGEST_CACHE_LIFETIME;
2794 } else {
2795 request_type = "/tor/server/?";
2797 (void) request_type; /* usable for note_request. */
2798 if (!strcmpstart(url, "d/"))
2799 conn->dir_spool_src =
2800 is_extra ? DIR_SPOOL_EXTRA_BY_DIGEST : DIR_SPOOL_SERVER_BY_DIGEST;
2801 else
2802 conn->dir_spool_src =
2803 is_extra ? DIR_SPOOL_EXTRA_BY_FP : DIR_SPOOL_SERVER_BY_FP;
2805 if (!dirserv_have_any_serverdesc(conn->fingerprint_stack,
2806 conn->dir_spool_src)) {
2807 res = -1;
2808 msg = "Not found";
2811 if (res < 0)
2812 write_http_status_line(conn, 404, msg);
2813 else {
2814 dlen = dirserv_estimate_data_size(conn->fingerprint_stack,
2815 1, compressed);
2816 if (global_write_bucket_low(TO_CONN(conn), dlen, 2)) {
2817 log_info(LD_DIRSERV,
2818 "Client asked for server descriptors, but we've been "
2819 "writing too many bytes lately. Sending 503 Dir busy.");
2820 write_http_status_line(conn, 503, "Directory busy, try again later");
2821 conn->dir_spool_src = DIR_SPOOL_NONE;
2822 goto done;
2824 write_http_response_header(conn, -1, compressed, cache_lifetime);
2825 if (compressed)
2826 conn->zlib_state = tor_zlib_new(1, ZLIB_METHOD);
2827 /* Prime the connection with some data. */
2828 connection_dirserv_flushed_some(conn);
2830 goto done;
2833 if (!strcmpstart(url,"/tor/keys/")) {
2834 smartlist_t *certs = smartlist_create();
2835 ssize_t len = -1;
2836 if (!strcmp(url, "/tor/keys/all")) {
2837 authority_cert_get_all(certs);
2838 } else if (!strcmp(url, "/tor/keys/authority")) {
2839 authority_cert_t *cert = get_my_v3_authority_cert();
2840 if (cert)
2841 smartlist_add(certs, cert);
2842 } else if (!strcmpstart(url, "/tor/keys/fp/")) {
2843 smartlist_t *fps = smartlist_create();
2844 dir_split_resource_into_fingerprints(url+strlen("/tor/keys/fp/"),
2845 fps, NULL,
2846 DSR_HEX|DSR_SORT_UNIQ);
2847 SMARTLIST_FOREACH(fps, char *, d, {
2848 authority_cert_t *c = authority_cert_get_newest_by_id(d);
2849 if (c) smartlist_add(certs, c);
2850 tor_free(d);
2852 smartlist_free(fps);
2853 } else if (!strcmpstart(url, "/tor/keys/sk/")) {
2854 smartlist_t *fps = smartlist_create();
2855 dir_split_resource_into_fingerprints(url+strlen("/tor/keys/sk/"),
2856 fps, NULL,
2857 DSR_HEX|DSR_SORT_UNIQ);
2858 SMARTLIST_FOREACH(fps, char *, d, {
2859 authority_cert_t *c = authority_cert_get_by_sk_digest(d);
2860 if (c) smartlist_add(certs, c);
2861 tor_free(d);
2863 smartlist_free(fps);
2864 } else if (!strcmpstart(url, "/tor/keys/fp-sk/")) {
2865 smartlist_t *fp_sks = smartlist_create();
2866 dir_split_resource_into_fingerprint_pairs(url+strlen("/tor/keys/fp-sk/"),
2867 fp_sks);
2868 SMARTLIST_FOREACH(fp_sks, fp_pair_t *, pair, {
2869 authority_cert_t *c = authority_cert_get_by_digests(pair->first,
2870 pair->second);
2871 if (c) smartlist_add(certs, c);
2872 tor_free(pair);
2874 smartlist_free(fp_sks);
2875 } else {
2876 write_http_status_line(conn, 400, "Bad request");
2877 goto keys_done;
2879 if (!smartlist_len(certs)) {
2880 write_http_status_line(conn, 404, "Not found");
2881 goto keys_done;
2883 SMARTLIST_FOREACH(certs, authority_cert_t *, c,
2884 if (c->cache_info.published_on < if_modified_since)
2885 SMARTLIST_DEL_CURRENT(certs, c));
2886 if (!smartlist_len(certs)) {
2887 write_http_status_line(conn, 304, "Not modified");
2888 goto keys_done;
2890 len = 0;
2891 SMARTLIST_FOREACH(certs, authority_cert_t *, c,
2892 len += c->cache_info.signed_descriptor_len);
2894 if (global_write_bucket_low(TO_CONN(conn), compressed?len/2:len, 2)) {
2895 write_http_status_line(conn, 503, "Directory busy, try again later.");
2896 goto keys_done;
2899 write_http_response_header(conn, compressed?-1:len, compressed, 60*60);
2900 if (compressed) {
2901 conn->zlib_state = tor_zlib_new(1, ZLIB_METHOD);
2902 SMARTLIST_FOREACH(certs, authority_cert_t *, c,
2903 connection_write_to_buf_zlib(c->cache_info.signed_descriptor_body,
2904 c->cache_info.signed_descriptor_len,
2905 conn, 0));
2906 connection_write_to_buf_zlib("", 0, conn, 1);
2907 } else {
2908 SMARTLIST_FOREACH(certs, authority_cert_t *, c,
2909 connection_write_to_buf(c->cache_info.signed_descriptor_body,
2910 c->cache_info.signed_descriptor_len,
2911 TO_CONN(conn)));
2913 keys_done:
2914 smartlist_free(certs);
2915 goto done;
2918 if (options->HidServDirectoryV2 &&
2919 !strcmpstart(url,"/tor/rendezvous2/")) {
2920 /* Handle v2 rendezvous descriptor fetch request. */
2921 const char *descp;
2922 const char *query = url + strlen("/tor/rendezvous2/");
2923 if (strlen(query) == REND_DESC_ID_V2_LEN_BASE32) {
2924 log_info(LD_REND, "Got a v2 rendezvous descriptor request for ID '%s'",
2925 safe_str(query));
2926 switch (rend_cache_lookup_v2_desc_as_dir(query, &descp)) {
2927 case 1: /* valid */
2928 write_http_response_header(conn, strlen(descp), 0, 0);
2929 connection_write_to_buf(descp, strlen(descp), TO_CONN(conn));
2930 break;
2931 case 0: /* well-formed but not present */
2932 write_http_status_line(conn, 404, "Not found");
2933 break;
2934 case -1: /* not well-formed */
2935 write_http_status_line(conn, 400, "Bad request");
2936 break;
2938 } else { /* not well-formed */
2939 write_http_status_line(conn, 400, "Bad request");
2941 goto done;
2944 if (options->HSAuthoritativeDir && !strcmpstart(url,"/tor/rendezvous/")) {
2945 /* rendezvous descriptor fetch */
2946 const char *descp;
2947 size_t desc_len;
2948 const char *query = url+strlen("/tor/rendezvous/");
2950 log_info(LD_REND, "Handling rendezvous descriptor get");
2951 switch (rend_cache_lookup_desc(query, 0, &descp, &desc_len)) {
2952 case 1: /* valid */
2953 write_http_response_header_impl(conn, desc_len,
2954 "application/octet-stream",
2955 NULL, NULL, 0);
2956 note_request("/tor/rendezvous?/", desc_len);
2957 /* need to send descp separately, because it may include NULs */
2958 connection_write_to_buf(descp, desc_len, TO_CONN(conn));
2959 break;
2960 case 0: /* well-formed but not present */
2961 write_http_status_line(conn, 404, "Not found");
2962 break;
2963 case -1: /* not well-formed */
2964 write_http_status_line(conn, 400, "Bad request");
2965 break;
2967 goto done;
2970 if (options->BridgeAuthoritativeDir &&
2971 options->BridgePassword &&
2972 connection_dir_is_encrypted(conn) &&
2973 !strcmp(url,"/tor/networkstatus-bridges")) {
2974 char *status;
2975 char *secret = alloc_http_authenticator(options->BridgePassword);
2977 header = http_get_header(headers, "Authorization: Basic ");
2979 /* now make sure the password is there and right */
2980 if (!header || strcmp(header, secret)) {
2981 write_http_status_line(conn, 404, "Not found");
2982 tor_free(secret);
2983 tor_free(header);
2984 goto done;
2986 tor_free(secret);
2987 tor_free(header);
2989 /* all happy now. send an answer. */
2990 status = networkstatus_getinfo_by_purpose("bridge", time(NULL));
2991 dlen = strlen(status);
2992 write_http_response_header(conn, dlen, 0, 0);
2993 connection_write_to_buf(status, dlen, TO_CONN(conn));
2994 tor_free(status);
2995 goto done;
2998 if (!strcmpstart(url,"/tor/bytes.txt")) {
2999 char *bytes = directory_dump_request_log();
3000 size_t len = strlen(bytes);
3001 write_http_response_header(conn, len, 0, 0);
3002 connection_write_to_buf(bytes, len, TO_CONN(conn));
3003 tor_free(bytes);
3004 goto done;
3007 if (!strcmp(url,"/tor/robots.txt")) { /* /robots.txt will have been
3008 rewritten to /tor/robots.txt */
3009 char robots[] = "User-agent: *\r\nDisallow: /\r\n";
3010 size_t len = strlen(robots);
3011 write_http_response_header(conn, len, 0, ROBOTS_CACHE_LIFETIME);
3012 connection_write_to_buf(robots, len, TO_CONN(conn));
3013 goto done;
3016 if (!strcmp(url,"/tor/dbg-stability.txt")) {
3017 const char *stability;
3018 size_t len;
3019 if (options->BridgeAuthoritativeDir ||
3020 ! authdir_mode_tests_reachability(options) ||
3021 ! (stability = rep_hist_get_router_stability_doc(time(NULL)))) {
3022 write_http_status_line(conn, 404, "Not found.");
3023 goto done;
3026 len = strlen(stability);
3027 write_http_response_header(conn, len, 0, 0);
3028 connection_write_to_buf(stability, len, TO_CONN(conn));
3029 goto done;
3032 #if defined(EXPORTMALLINFO) && defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO)
3033 #define ADD_MALLINFO_LINE(x) do { \
3034 tor_snprintf(tmp, sizeof(tmp), "%s %d\n", #x, mi.x); \
3035 smartlist_add(lines, tor_strdup(tmp)); \
3036 }while(0);
3038 if (!strcmp(url,"/tor/mallinfo.txt") &&
3039 (tor_addr_eq_ipv4h(&conn->_base.addr, 0x7f000001ul))) {
3040 char *result;
3041 size_t len;
3042 struct mallinfo mi;
3043 smartlist_t *lines;
3044 char tmp[256];
3046 memset(&mi, 0, sizeof(mi));
3047 mi = mallinfo();
3048 lines = smartlist_create();
3050 ADD_MALLINFO_LINE(arena)
3051 ADD_MALLINFO_LINE(ordblks)
3052 ADD_MALLINFO_LINE(smblks)
3053 ADD_MALLINFO_LINE(hblks)
3054 ADD_MALLINFO_LINE(hblkhd)
3055 ADD_MALLINFO_LINE(usmblks)
3056 ADD_MALLINFO_LINE(fsmblks)
3057 ADD_MALLINFO_LINE(uordblks)
3058 ADD_MALLINFO_LINE(fordblks)
3059 ADD_MALLINFO_LINE(keepcost)
3061 result = smartlist_join_strings(lines, "", 0, NULL);
3062 SMARTLIST_FOREACH(lines, char *, cp, tor_free(cp));
3063 smartlist_free(lines);
3065 len = strlen(result);
3066 write_http_response_header(conn, len, 0, 0);
3067 connection_write_to_buf(result, len, TO_CONN(conn));
3068 tor_free(result);
3069 goto done;
3071 #endif
3073 /* we didn't recognize the url */
3074 write_http_status_line(conn, 404, "Not found");
3076 done:
3077 tor_free(url_mem);
3078 return 0;
3081 /** Helper function: called when a dirserver gets a complete HTTP POST
3082 * request. Look for an uploaded server descriptor or rendezvous
3083 * service descriptor. On finding one, process it and write a
3084 * response into conn-\>outbuf. If the request is unrecognized, send a
3085 * 400. Always return 0. */
3086 static int
3087 directory_handle_command_post(dir_connection_t *conn, const char *headers,
3088 const char *body, size_t body_len)
3090 char *url = NULL;
3091 or_options_t *options = get_options();
3093 log_debug(LD_DIRSERV,"Received POST command.");
3095 conn->_base.state = DIR_CONN_STATE_SERVER_WRITING;
3097 if (parse_http_url(headers, &url) < 0) {
3098 write_http_status_line(conn, 400, "Bad request");
3099 return 0;
3101 log_debug(LD_DIRSERV,"rewritten url as '%s'.", url);
3103 /* Handle v2 rendezvous service publish request. */
3104 if (options->HidServDirectoryV2 &&
3105 !strcmpstart(url,"/tor/rendezvous2/publish")) {
3106 switch (rend_cache_store_v2_desc_as_dir(body)) {
3107 case -2:
3108 log_info(LD_REND, "Rejected v2 rend descriptor (length %d) from %s "
3109 "since we're not currently a hidden service directory.",
3110 (int)body_len, conn->_base.address);
3111 write_http_status_line(conn, 503, "Currently not acting as v2 "
3112 "hidden service directory");
3113 break;
3114 case -1:
3115 log_warn(LD_REND, "Rejected v2 rend descriptor (length %d) from %s.",
3116 (int)body_len, conn->_base.address);
3117 write_http_status_line(conn, 400,
3118 "Invalid v2 service descriptor rejected");
3119 break;
3120 default:
3121 write_http_status_line(conn, 200, "Service descriptor (v2) stored");
3122 log_info(LD_REND, "Handled v2 rendezvous descriptor post: accepted");
3124 goto done;
3127 if (!authdir_mode(options)) {
3128 /* we just provide cached directories; we don't want to
3129 * receive anything. */
3130 write_http_status_line(conn, 400, "Nonauthoritative directory does not "
3131 "accept posted server descriptors");
3132 goto done;
3135 if (authdir_mode_handles_descs(options, -1) &&
3136 !strcmp(url,"/tor/")) { /* server descriptor post */
3137 const char *msg = "[None]";
3138 uint8_t purpose = authdir_mode_bridge(options) ?
3139 ROUTER_PURPOSE_BRIDGE : ROUTER_PURPOSE_GENERAL;
3140 was_router_added_t r = dirserv_add_multiple_descriptors(body, purpose,
3141 conn->_base.address, &msg);
3142 tor_assert(msg);
3143 if (WRA_WAS_ADDED(r))
3144 dirserv_get_directory(); /* rebuild and write to disk */
3146 if (r == ROUTER_ADDED_NOTIFY_GENERATOR) {
3147 /* Accepted with a message. */
3148 log_info(LD_DIRSERV,
3149 "Problematic router descriptor or extra-info from %s "
3150 "(\"%s\").",
3151 conn->_base.address, msg);
3152 write_http_status_line(conn, 400, msg);
3153 } else if (r == ROUTER_ADDED_SUCCESSFULLY) {
3154 write_http_status_line(conn, 200, msg);
3155 } else if (WRA_WAS_OUTDATED(r)) {
3156 write_http_response_header_impl(conn, -1, NULL, NULL,
3157 "X-Descriptor-Not-New: Yes\r\n", -1);
3158 } else {
3159 log_info(LD_DIRSERV,
3160 "Rejected router descriptor or extra-info from %s "
3161 "(\"%s\").",
3162 conn->_base.address, msg);
3163 write_http_status_line(conn, 400, msg);
3165 goto done;
3168 if (options->HSAuthoritativeDir &&
3169 !strcmpstart(url,"/tor/rendezvous/publish")) {
3170 /* rendezvous descriptor post */
3171 log_info(LD_REND, "Handling rendezvous descriptor post.");
3172 if (rend_cache_store(body, body_len, 1) < 0) {
3173 log_fn(LOG_PROTOCOL_WARN, LD_DIRSERV,
3174 "Rejected rend descriptor (length %d) from %s.",
3175 (int)body_len, conn->_base.address);
3176 write_http_status_line(conn, 400,
3177 "Invalid v0 service descriptor rejected");
3178 } else {
3179 write_http_status_line(conn, 200, "Service descriptor (v0) stored");
3181 goto done;
3184 if (authdir_mode_v3(options) &&
3185 !strcmp(url,"/tor/post/vote")) { /* v3 networkstatus vote */
3186 const char *msg = "OK";
3187 int status;
3188 if (dirvote_add_vote(body, &msg, &status)) {
3189 write_http_status_line(conn, status, "Vote stored");
3190 } else {
3191 tor_assert(msg);
3192 write_http_status_line(conn, status, msg);
3194 goto done;
3197 if (authdir_mode_v3(options) &&
3198 !strcmp(url,"/tor/post/consensus-signature")) { /* sigs on consensus. */
3199 const char *msg = NULL;
3200 if (dirvote_add_signatures(body, conn->_base.address, &msg)>=0) {
3201 write_http_status_line(conn, 200, msg?msg:"Signatures stored");
3202 } else {
3203 log_warn(LD_DIR, "Unable to store signatures posted by %s: %s",
3204 conn->_base.address, msg?msg:"???");
3205 write_http_status_line(conn, 400, msg?msg:"Unable to store signatures");
3207 goto done;
3210 /* we didn't recognize the url */
3211 write_http_status_line(conn, 404, "Not found");
3213 done:
3214 tor_free(url);
3215 return 0;
3218 /** Called when a dirserver receives data on a directory connection;
3219 * looks for an HTTP request. If the request is complete, remove it
3220 * from the inbuf, try to process it; otherwise, leave it on the
3221 * buffer. Return a 0 on success, or -1 on error.
3223 static int
3224 directory_handle_command(dir_connection_t *conn)
3226 char *headers=NULL, *body=NULL;
3227 size_t body_len=0;
3228 int r;
3230 tor_assert(conn);
3231 tor_assert(conn->_base.type == CONN_TYPE_DIR);
3233 switch (fetch_from_buf_http(conn->_base.inbuf,
3234 &headers, MAX_HEADERS_SIZE,
3235 &body, &body_len, MAX_DIR_UL_SIZE, 0)) {
3236 case -1: /* overflow */
3237 log_warn(LD_DIRSERV,
3238 "Request too large from address '%s' to DirPort. Closing.",
3239 safe_str(conn->_base.address));
3240 return -1;
3241 case 0:
3242 log_debug(LD_DIRSERV,"command not all here yet.");
3243 return 0;
3244 /* case 1, fall through */
3247 http_set_address_origin(headers, TO_CONN(conn));
3248 //log_debug(LD_DIRSERV,"headers %s, body %s.", headers, body);
3250 if (!strncasecmp(headers,"GET",3))
3251 r = directory_handle_command_get(conn, headers, body, body_len);
3252 else if (!strncasecmp(headers,"POST",4))
3253 r = directory_handle_command_post(conn, headers, body, body_len);
3254 else {
3255 log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
3256 "Got headers %s with unknown command. Closing.",
3257 escaped(headers));
3258 r = -1;
3261 tor_free(headers); tor_free(body);
3262 return r;
3265 /** Write handler for directory connections; called when all data has
3266 * been flushed. Close the connection or wait for a response as
3267 * appropriate.
3270 connection_dir_finished_flushing(dir_connection_t *conn)
3272 tor_assert(conn);
3273 tor_assert(conn->_base.type == CONN_TYPE_DIR);
3275 /* Note that we have finished writing the directory response. For direct
3276 * connections this means we're done, for tunneled connections its only
3277 * an intermediate step. */
3278 if (TO_CONN(conn)->dirreq_id)
3279 geoip_change_dirreq_state(TO_CONN(conn)->dirreq_id, DIRREQ_TUNNELED,
3280 DIRREQ_FLUSHING_DIR_CONN_FINISHED);
3281 else
3282 geoip_change_dirreq_state(TO_CONN(conn)->global_identifier,
3283 DIRREQ_DIRECT,
3284 DIRREQ_FLUSHING_DIR_CONN_FINISHED);
3285 switch (conn->_base.state) {
3286 case DIR_CONN_STATE_CLIENT_SENDING:
3287 log_debug(LD_DIR,"client finished sending command.");
3288 conn->_base.state = DIR_CONN_STATE_CLIENT_READING;
3289 connection_stop_writing(TO_CONN(conn));
3290 return 0;
3291 case DIR_CONN_STATE_SERVER_WRITING:
3292 log_debug(LD_DIRSERV,"Finished writing server response. Closing.");
3293 connection_mark_for_close(TO_CONN(conn));
3294 return 0;
3295 default:
3296 log_warn(LD_BUG,"called in unexpected state %d.",
3297 conn->_base.state);
3298 tor_fragile_assert();
3299 return -1;
3301 return 0;
3304 /** Connected handler for directory connections: begin sending data to the
3305 * server */
3307 connection_dir_finished_connecting(dir_connection_t *conn)
3309 tor_assert(conn);
3310 tor_assert(conn->_base.type == CONN_TYPE_DIR);
3311 tor_assert(conn->_base.state == DIR_CONN_STATE_CONNECTING);
3313 log_debug(LD_HTTP,"Dir connection to router %s:%u established.",
3314 conn->_base.address,conn->_base.port);
3316 conn->_base.state = DIR_CONN_STATE_CLIENT_SENDING; /* start flushing conn */
3317 return 0;
3320 /** Called when one or more networkstatus fetches have failed (with uppercase
3321 * fingerprints listed in <b>failed</b>). Mark those fingerprints as having
3322 * failed once, unless they failed with status code 503. */
3323 static void
3324 dir_networkstatus_download_failed(smartlist_t *failed, int status_code)
3326 if (status_code == 503)
3327 return;
3328 SMARTLIST_FOREACH(failed, const char *, fp,
3330 char digest[DIGEST_LEN];
3331 trusted_dir_server_t *dir;
3332 if (base16_decode(digest, DIGEST_LEN, fp, strlen(fp))<0) {
3333 log_warn(LD_BUG, "Called with bad fingerprint in list: %s",
3334 escaped(fp));
3335 continue;
3337 dir = router_get_trusteddirserver_by_digest(digest);
3339 if (dir)
3340 download_status_failed(&dir->v2_ns_dl_status, status_code);
3344 /** Schedule for when servers should download things in general. */
3345 static const int server_dl_schedule[] = {
3346 0, 0, 0, 60, 60, 60*2, 60*5, 60*15, INT_MAX
3348 /** Schedule for when clients should download things in general. */
3349 static const int client_dl_schedule[] = {
3350 0, 0, 60, 60*5, 60*10, INT_MAX
3352 /** Schedule for when servers should download consensuses. */
3353 static const int server_consensus_dl_schedule[] = {
3354 0, 0, 60, 60*5, 60*10, 60*30, 60*30, 60*30, 60*30, 60*30, 60*60, 60*60*2
3356 /** Schedule for when clients should download consensuses. */
3357 static const int client_consensus_dl_schedule[] = {
3358 0, 0, 60, 60*5, 60*10, 60*30, 60*60, 60*60, 60*60, 60*60*3, 60*60*6, 60*60*12
3360 /** Schedule for when clients should download bridge descriptors. */
3361 static const int bridge_dl_schedule[] = {
3362 60*60, 15*60, 15*60, 60*60
3365 /** Decide which download schedule we want to use, and then return a
3366 * pointer to it along with a pointer to its length. Helper function for
3367 * download_status_increment_failure() and download_status_reset(). */
3368 static void
3369 find_dl_schedule_and_len(download_status_t *dls, int server,
3370 const int **schedule, size_t *schedule_len)
3372 switch (dls->schedule) {
3373 case DL_SCHED_GENERIC:
3374 if (server) {
3375 *schedule = server_dl_schedule;
3376 *schedule_len = sizeof(server_dl_schedule)/sizeof(int);
3377 } else {
3378 *schedule = client_dl_schedule;
3379 *schedule_len = sizeof(client_dl_schedule)/sizeof(int);
3381 break;
3382 case DL_SCHED_CONSENSUS:
3383 if (server) {
3384 *schedule = server_consensus_dl_schedule;
3385 *schedule_len = sizeof(server_consensus_dl_schedule)/sizeof(int);
3386 } else {
3387 *schedule = client_consensus_dl_schedule;
3388 *schedule_len = sizeof(client_consensus_dl_schedule)/sizeof(int);
3390 break;
3391 case DL_SCHED_BRIDGE:
3392 *schedule = bridge_dl_schedule;
3393 *schedule_len = sizeof(bridge_dl_schedule)/sizeof(int);
3394 break;
3395 default:
3396 tor_assert(0);
3400 /** Called when an attempt to download <b>dls</b> has failed with HTTP status
3401 * <b>status_code</b>. Increment the failure count (if the code indicates a
3402 * real failure) and set <b>dls</b>-\>next_attempt_at to an appropriate time
3403 * in the future. */
3404 time_t
3405 download_status_increment_failure(download_status_t *dls, int status_code,
3406 const char *item, int server, time_t now)
3408 const int *schedule;
3409 size_t schedule_len;
3410 int increment;
3411 tor_assert(dls);
3412 if (status_code != 503 || server) {
3413 if (dls->n_download_failures < IMPOSSIBLE_TO_DOWNLOAD-1)
3414 ++dls->n_download_failures;
3417 find_dl_schedule_and_len(dls, server, &schedule, &schedule_len);
3419 if (dls->n_download_failures < schedule_len)
3420 increment = schedule[dls->n_download_failures];
3421 else if (dls->n_download_failures == IMPOSSIBLE_TO_DOWNLOAD)
3422 increment = INT_MAX;
3423 else
3424 increment = schedule[schedule_len-1];
3426 if (increment < INT_MAX)
3427 dls->next_attempt_at = now+increment;
3428 else
3429 dls->next_attempt_at = TIME_MAX;
3431 if (item) {
3432 if (increment == 0)
3433 log_debug(LD_DIR, "%s failed %d time(s); I'll try again immediately.",
3434 item, (int)dls->n_download_failures);
3435 else if (dls->next_attempt_at < TIME_MAX)
3436 log_debug(LD_DIR, "%s failed %d time(s); I'll try again in %d seconds.",
3437 item, (int)dls->n_download_failures,
3438 (int)(dls->next_attempt_at-now));
3439 else
3440 log_debug(LD_DIR, "%s failed %d time(s); Giving up for a while.",
3441 item, (int)dls->n_download_failures);
3443 return dls->next_attempt_at;
3446 /** Reset <b>dls</b> so that it will be considered downloadable
3447 * immediately, and/or to show that we don't need it anymore.
3449 * (We find the zeroth element of the download schedule, and set
3450 * next_attempt_at to be the appropriate offset from 'now'. In most
3451 * cases this means setting it to 'now', so the item will be immediately
3452 * downloadable; in the case of bridge descriptors, the zeroth element
3453 * is an hour from now.) */
3454 void
3455 download_status_reset(download_status_t *dls)
3457 const int *schedule;
3458 size_t schedule_len;
3460 find_dl_schedule_and_len(dls, get_options()->DirPort,
3461 &schedule, &schedule_len);
3463 dls->n_download_failures = 0;
3464 dls->next_attempt_at = time(NULL) + schedule[0];
3467 /** Called when one or more routerdesc (or extrainfo, if <b>was_extrainfo</b>)
3468 * fetches have failed (with uppercase fingerprints listed in <b>failed</b>,
3469 * either as descriptor digests or as identity digests based on
3470 * <b>was_descriptor_digests</b>).
3472 static void
3473 dir_routerdesc_download_failed(smartlist_t *failed, int status_code,
3474 int router_purpose,
3475 int was_extrainfo, int was_descriptor_digests)
3477 char digest[DIGEST_LEN];
3478 time_t now = time(NULL);
3479 int server = directory_fetches_from_authorities(get_options());
3480 if (!was_descriptor_digests) {
3481 if (router_purpose == ROUTER_PURPOSE_BRIDGE) {
3482 tor_assert(!was_extrainfo); /* not supported yet */
3483 SMARTLIST_FOREACH(failed, const char *, cp,
3485 if (base16_decode(digest, DIGEST_LEN, cp, strlen(cp))<0) {
3486 log_warn(LD_BUG, "Malformed fingerprint in list: %s",
3487 escaped(cp));
3488 continue;
3490 retry_bridge_descriptor_fetch_directly(digest);
3493 return; /* FFFF should implement for other-than-router-purpose someday */
3495 SMARTLIST_FOREACH(failed, const char *, cp,
3497 download_status_t *dls = NULL;
3498 if (base16_decode(digest, DIGEST_LEN, cp, strlen(cp)) < 0) {
3499 log_warn(LD_BUG, "Malformed fingerprint in list: %s", escaped(cp));
3500 continue;
3502 if (was_extrainfo) {
3503 signed_descriptor_t *sd =
3504 router_get_by_extrainfo_digest(digest);
3505 if (sd)
3506 dls = &sd->ei_dl_status;
3507 } else {
3508 dls = router_get_dl_status_by_descriptor_digest(digest);
3510 if (!dls || dls->n_download_failures >= MAX_ROUTERDESC_DOWNLOAD_FAILURES)
3511 continue;
3512 download_status_increment_failure(dls, status_code, cp, server, now);
3515 /* No need to relaunch descriptor downloads here: we already do it
3516 * every 10 or 60 seconds (FOO_DESCRIPTOR_RETRY_INTERVAL) in main.c. */
3519 /** Helper. Compare two fp_pair_t objects, and return -1, 0, or 1 as
3520 * appropriate. */
3521 static int
3522 _compare_pairs(const void **a, const void **b)
3524 const fp_pair_t *fp1 = *a, *fp2 = *b;
3525 int r;
3526 if ((r = memcmp(fp1->first, fp2->first, DIGEST_LEN)))
3527 return r;
3528 else
3529 return memcmp(fp1->second, fp2->second, DIGEST_LEN);
3532 /** Divide a string <b>res</b> of the form FP1-FP2+FP3-FP4...[.z], where each
3533 * FP is a hex-encoded fingerprint, into a sequence of distinct sorted
3534 * fp_pair_t. Skip malformed pairs. On success, return 0 and add those
3535 * fp_pair_t into <b>pairs_out</b>. On failure, return -1. */
3537 dir_split_resource_into_fingerprint_pairs(const char *res,
3538 smartlist_t *pairs_out)
3540 smartlist_t *pairs_tmp = smartlist_create();
3541 smartlist_t *pairs_result = smartlist_create();
3543 smartlist_split_string(pairs_tmp, res, "+", 0, 0);
3544 if (smartlist_len(pairs_tmp)) {
3545 char *last = smartlist_get(pairs_tmp,smartlist_len(pairs_tmp)-1);
3546 size_t last_len = strlen(last);
3547 if (last_len > 2 && !strcmp(last+last_len-2, ".z")) {
3548 last[last_len-2] = '\0';
3551 SMARTLIST_FOREACH_BEGIN(pairs_tmp, char *, cp) {
3552 if (strlen(cp) != HEX_DIGEST_LEN*2+1) {
3553 log_info(LD_DIR,
3554 "Skipping digest pair %s with non-standard length.", escaped(cp));
3555 } else if (cp[HEX_DIGEST_LEN] != '-') {
3556 log_info(LD_DIR,
3557 "Skipping digest pair %s with missing dash.", escaped(cp));
3558 } else {
3559 fp_pair_t pair;
3560 if (base16_decode(pair.first, DIGEST_LEN, cp, HEX_DIGEST_LEN)<0 ||
3561 base16_decode(pair.second,
3562 DIGEST_LEN, cp+HEX_DIGEST_LEN+1, HEX_DIGEST_LEN)<0) {
3563 log_info(LD_DIR, "Skipping non-decodable digest pair %s", escaped(cp));
3564 } else {
3565 smartlist_add(pairs_result, tor_memdup(&pair, sizeof(pair)));
3568 tor_free(cp);
3569 } SMARTLIST_FOREACH_END(cp);
3570 smartlist_free(pairs_tmp);
3572 /* Uniq-and-sort */
3573 smartlist_sort(pairs_result, _compare_pairs);
3574 smartlist_uniq(pairs_result, _compare_pairs, _tor_free);
3576 smartlist_add_all(pairs_out, pairs_result);
3577 smartlist_free(pairs_result);
3578 return 0;
3581 /** Given a directory <b>resource</b> request, containing zero
3582 * or more strings separated by plus signs, followed optionally by ".z", store
3583 * the strings, in order, into <b>fp_out</b>. If <b>compressed_out</b> is
3584 * non-NULL, set it to 1 if the resource ends in ".z", else set it to 0.
3586 * If (flags & DSR_HEX), then delete all elements that aren't hex digests, and
3587 * decode the rest. If (flags & DSR_BASE64), then use "-" rather than "+" as
3588 * a separator, delete all the elements that aren't base64-encoded digests,
3589 * and decode the rest. If (flags & DSR_DIGEST256), these digests should be
3590 * 256 bits long; else they should be 160.
3592 * If (flags & DSR_SORT_UNIQ), then sort the list and remove all duplicates.
3595 dir_split_resource_into_fingerprints(const char *resource,
3596 smartlist_t *fp_out, int *compressed_out,
3597 int flags)
3599 const int decode_hex = flags & DSR_HEX;
3600 const int decode_base64 = flags & DSR_BASE64;
3601 const int digests_are_256 = flags & DSR_DIGEST256;
3602 const int sort_uniq = flags & DSR_SORT_UNIQ;
3604 const int digest_len = digests_are_256 ? DIGEST256_LEN : DIGEST_LEN;
3605 const int hex_digest_len = digests_are_256 ?
3606 HEX_DIGEST256_LEN : HEX_DIGEST_LEN;
3607 const int base64_digest_len = digests_are_256 ?
3608 BASE64_DIGEST256_LEN : BASE64_DIGEST_LEN;
3609 smartlist_t *fp_tmp = smartlist_create();
3611 tor_assert(!(decode_hex && decode_base64));
3612 tor_assert(fp_out);
3614 smartlist_split_string(fp_tmp, resource, decode_base64?"-":"+", 0, 0);
3615 if (compressed_out)
3616 *compressed_out = 0;
3617 if (smartlist_len(fp_tmp)) {
3618 char *last = smartlist_get(fp_tmp,smartlist_len(fp_tmp)-1);
3619 size_t last_len = strlen(last);
3620 if (last_len > 2 && !strcmp(last+last_len-2, ".z")) {
3621 last[last_len-2] = '\0';
3622 if (compressed_out)
3623 *compressed_out = 1;
3626 if (decode_hex || decode_base64) {
3627 const size_t encoded_len = decode_hex ? hex_digest_len : base64_digest_len;
3628 int i;
3629 char *cp, *d = NULL;
3630 for (i = 0; i < smartlist_len(fp_tmp); ++i) {
3631 cp = smartlist_get(fp_tmp, i);
3632 if (strlen(cp) != encoded_len) {
3633 log_info(LD_DIR,
3634 "Skipping digest %s with non-standard length.", escaped(cp));
3635 smartlist_del_keeporder(fp_tmp, i--);
3636 goto again;
3638 d = tor_malloc_zero(digest_len);
3639 if (decode_hex ?
3640 (base16_decode(d, digest_len, cp, hex_digest_len)<0) :
3641 (base64_decode(d, digest_len, cp, base64_digest_len)<0)) {
3642 log_info(LD_DIR, "Skipping non-decodable digest %s", escaped(cp));
3643 smartlist_del_keeporder(fp_tmp, i--);
3644 goto again;
3646 smartlist_set(fp_tmp, i, d);
3647 d = NULL;
3648 again:
3649 tor_free(cp);
3650 tor_free(d);
3653 if (sort_uniq) {
3654 if (decode_hex || decode_base64) {
3655 if (digests_are_256) {
3656 smartlist_sort_digests256(fp_tmp);
3657 smartlist_uniq_digests256(fp_tmp);
3658 } else {
3659 smartlist_sort_digests(fp_tmp);
3660 smartlist_uniq_digests(fp_tmp);
3662 } else {
3663 smartlist_sort_strings(fp_tmp);
3664 smartlist_uniq_strings(fp_tmp);
3667 smartlist_add_all(fp_out, fp_tmp);
3668 smartlist_free(fp_tmp);
3669 return 0;