Tor 0.4.9.1-alpha-dev
dircache.c
Go to the documentation of this file.
1/* Copyright (c) 2001-2004, Roger Dingledine.
2 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
3 * Copyright (c) 2007-2021, The Tor Project, Inc. */
4/* See LICENSE for licensing information */
5
6/**
7 * @file dircache.c
8 * @brief Cache directories and serve them to clients.
9 **/
10
11#define DIRCACHE_PRIVATE
12
13#include "core/or/or.h"
14
15#include "app/config/config.h"
18#include "core/or/relay.h"
28#include "feature/hs/hs_cache.h"
29#include "feature/hs/hs_ident.h"
39
45
46/** Maximum size, in bytes, for any directory object that we're accepting
47 * as an upload. */
48#define MAX_DIR_UL_SIZE ((1<<24)-1) /* 16MB-1 */
49
50/** HTTP cache control: how long do we tell proxies they can cache each
51 * kind of document we serve? */
52#define FULL_DIR_CACHE_LIFETIME (60*60)
53#define RUNNINGROUTERS_CACHE_LIFETIME (20*60)
54#define DIRPORTFRONTPAGE_CACHE_LIFETIME (20*60)
55#define NETWORKSTATUS_CACHE_LIFETIME (5*60)
56#define ROUTERDESC_CACHE_LIFETIME (30*60)
57#define ROUTERDESC_BY_DIGEST_CACHE_LIFETIME (48*60*60)
58#define ROBOTS_CACHE_LIFETIME (24*60*60)
59#define MICRODESC_CACHE_LIFETIME (48*60*60)
60/* Bandwidth files change every hour. */
61#define BANDWIDTH_CACHE_LIFETIME (30*60)
62/** Parse an HTTP request string <b>headers</b> of the form
63 * \verbatim
64 * "\%s [http[s]://]\%s HTTP/1..."
65 * \endverbatim
66 * If it's well-formed, strdup the second \%s into *<b>url</b>, and
67 * nul-terminate it. If the url doesn't start with "/tor/", rewrite it
68 * so it does. Return 0.
69 * Otherwise, return -1.
70 */
71STATIC int
72parse_http_url(const char *headers, char **url)
73{
74 char *command = NULL;
75 if (parse_http_command(headers, &command, url) < 0) {
76 return -1;
77 }
78 if (strcmpstart(*url, "/tor/")) {
79 char *new_url = NULL;
80 tor_asprintf(&new_url, "/tor%s%s",
81 *url[0] == '/' ? "" : "/",
82 *url);
83 tor_free(*url);
84 *url = new_url;
85 }
87 return 0;
88}
89
90/** Create an http response for the client <b>conn</b> out of
91 * <b>status</b> and <b>reason_phrase</b>. Write it to <b>conn</b>.
92 */
93static void
95 const char *reason_phrase)
96{
97 char *buf = NULL;
98 char *datestring = NULL;
99
100 IF_BUG_ONCE(!reason_phrase) { /* bullet-proofing */
101 reason_phrase = "unspecified";
102 }
103
104 if (server_mode(get_options())) {
105 /* include the Date: header, but only if we're a relay or bridge */
106 char datebuf[RFC1123_TIME_LEN+1];
107 format_rfc1123_time(datebuf, time(NULL));
108 tor_asprintf(&datestring, "Date: %s\r\n", datebuf);
109 }
110
111 tor_asprintf(&buf, "HTTP/1.0 %d %s\r\n%s\r\n",
112 status, reason_phrase, datestring?datestring:"");
113
114 log_debug(LD_DIRSERV,"Wrote status 'HTTP/1.0 %d %s'", status, reason_phrase);
115 connection_buf_add(buf, strlen(buf), TO_CONN(conn));
116
117 tor_free(datestring);
118 tor_free(buf);
119}
120
121/** Write the header for an HTTP/1.0 response onto <b>conn</b>->outbuf,
122 * with <b>type</b> as the Content-Type.
123 *
124 * If <b>length</b> is nonnegative, it is the Content-Length.
125 * If <b>encoding</b> is provided, it is the Content-Encoding.
126 * If <b>cache_lifetime</b> is greater than 0, the content may be cached for
127 * up to cache_lifetime seconds. Otherwise, the content may not be cached. */
128static void
130 const char *type, const char *encoding,
131 const char *extra_headers,
132 long cache_lifetime)
133{
134 char date[RFC1123_TIME_LEN+1];
135 time_t now = approx_time();
136 buf_t *buf = buf_new_with_capacity(1024);
137
138 tor_assert(conn);
139
140 format_rfc1123_time(date, now);
141
142 buf_add_printf(buf, "HTTP/1.0 200 OK\r\nDate: %s\r\n", date);
143 if (type) {
144 buf_add_printf(buf, "Content-Type: %s\r\n", type);
145 }
146 if (!is_local_to_resolve_addr(&conn->base_.addr)) {
147 /* Don't report the source address for a nearby/private connection.
148 * Otherwise we tend to mis-report in cases where incoming ports are
149 * being forwarded to a Tor server running behind the firewall. */
150 buf_add_printf(buf, X_ADDRESS_HEADER "%s\r\n", conn->base_.address);
151 }
152 if (encoding) {
153 buf_add_printf(buf, "Content-Encoding: %s\r\n", encoding);
154 }
155 if (length >= 0) {
156 buf_add_printf(buf, "Content-Length: %ld\r\n", (long)length);
157 }
158 if (cache_lifetime > 0) {
159 char expbuf[RFC1123_TIME_LEN+1];
160 format_rfc1123_time(expbuf, (time_t)(now + cache_lifetime));
161 /* We could say 'Cache-control: max-age=%d' here if we start doing
162 * http/1.1 */
163 buf_add_printf(buf, "Expires: %s\r\n", expbuf);
164 } else if (cache_lifetime == 0) {
165 /* We could say 'Cache-control: no-cache' here if we start doing
166 * http/1.1 */
167 buf_add_string(buf, "Pragma: no-cache\r\n");
168 }
169 if (extra_headers) {
170 buf_add_string(buf, extra_headers);
171 }
172 buf_add_string(buf, "\r\n");
173
175 buf_free(buf);
176}
177
178/** As write_http_response_header_impl, but translates method into
179 * encoding */
180static void
182 compress_method_t method,
183 const char *extra_headers, long cache_lifetime)
184{
186 "text/plain",
188 extra_headers,
189 cache_lifetime);
190}
191
192/** As write_http_response_headers, but assumes extra_headers is NULL */
193static void
195 compress_method_t method,
196 long cache_lifetime)
197{
198 write_http_response_headers(conn, length, method, NULL, cache_lifetime);
199}
200
201/** Array of compression methods to use (if supported) for serving
202 * precompressed data, ordered from best to worst. */
204 LZMA_METHOD,
205 ZSTD_METHOD,
206 ZLIB_METHOD,
207 GZIP_METHOD,
208 NO_METHOD
209};
210
211/** Array of compression methods to use (if supported) for serving
212 * streamed data, ordered from best to worst. */
214 ZSTD_METHOD,
215 ZLIB_METHOD,
216 GZIP_METHOD,
217 NO_METHOD
218};
219
220/** Parse the compression methods listed in an Accept-Encoding header <b>h</b>,
221 * and convert them to a bitfield where compression method x is supported if
222 * and only if 1 &lt;&lt; x is set in the bitfield. */
223STATIC unsigned
225{
226 unsigned result = (1u << NO_METHOD);
227 smartlist_t *methods = smartlist_new();
228 smartlist_split_string(methods, h, ",",
229 SPLIT_SKIP_SPACE|SPLIT_STRIP_SPACE|SPLIT_IGNORE_BLANK, 0);
230
231 SMARTLIST_FOREACH_BEGIN(methods, const char *, m) {
233 if (method != UNKNOWN_METHOD) {
234 tor_assert(((unsigned)method) < 8*sizeof(unsigned));
235 result |= (1u << method);
236 }
237 } SMARTLIST_FOREACH_END(m);
238 SMARTLIST_FOREACH_BEGIN(methods, char *, m) {
239 tor_free(m);
240 } SMARTLIST_FOREACH_END(m);
241 smartlist_free(methods);
242 return result;
243}
244
245/** Decide whether a client would accept the consensus we have.
246 *
247 * Clients can say they only want a consensus if it's signed by more
248 * than half the authorities in a list. They pass this list in
249 * the url as "...consensus/<b>fpr</b>+<b>fpr</b>+<b>fpr</b>".
250 *
251 * <b>fpr</b> may be an abbreviated fingerprint, i.e. only a left substring
252 * of the full authority identity digest. (Only strings of even length,
253 * i.e. encodings of full bytes, are handled correctly. In the case
254 * of an odd number of hex digits the last one is silently ignored.)
255 *
256 * Returns 1 if more than half of the requested authorities signed the
257 * consensus, 0 otherwise.
258 */
259static int
261 const char *want_url)
262{
263 smartlist_t *voters = smartlist_new();
264 int need_at_least;
265 int have = 0;
266
267 if (consensus_cache_entry_get_voter_id_digests(ent, voters) != 0) {
268 smartlist_free(voters);
269 return 1; // We don't know the voters; assume the client won't mind. */
270 }
271
272 smartlist_t *want_authorities = smartlist_new();
273 dir_split_resource_into_fingerprints(want_url, want_authorities, NULL, 0);
274 need_at_least = smartlist_len(want_authorities)/2+1;
275
276 SMARTLIST_FOREACH_BEGIN(want_authorities, const char *, want_digest) {
277
278 SMARTLIST_FOREACH_BEGIN(voters, const char *, digest) {
279 if (!strcasecmpstart(digest, want_digest)) {
280 have++;
281 break;
282 };
283 } SMARTLIST_FOREACH_END(digest);
284
285 /* early exit, if we already have enough */
286 if (have >= need_at_least)
287 break;
288 } SMARTLIST_FOREACH_END(want_digest);
289
290 SMARTLIST_FOREACH(want_authorities, char *, d, tor_free(d));
291 smartlist_free(want_authorities);
292 SMARTLIST_FOREACH(voters, char *, cp, tor_free(cp));
293 smartlist_free(voters);
294 return (have >= need_at_least);
295}
296
297/** Return the compression level we should use for sending a compressed
298 * response of size <b>n_bytes</b>. */
301{
302 /* This is the compression level choice for a stream.
303 *
304 * We always return LOW because this compression is done in the main thread
305 * thus we save CPU time as much as possible, and it is also done more than
306 * background compression for document we serve pre-compressed.
307 *
308 * GZip highest compression level (9) gives us a ratio of 49.72%
309 * Zstd lowest compression level (1) gives us a ratio of 47.38%
310 *
311 * Thus, as the network moves more and more to use Zstd when requesting
312 * directory documents that are not pre-cached, even at the
313 * lowest level, we still gain over GZip and thus help with load and CPU
314 * time on the network. */
315 return LOW_COMPRESSION;
316}
317
318/** Information passed to handle a GET request. */
319typedef struct get_handler_args_t {
320 /** Bitmask of compression methods that the client said (or implied) it
321 * supported. */
323 /** If nonzero, the time included an if-modified-since header with this
324 * value. */
326 /** String containing the requested URL or resource. */
327 const char *url;
328 /** String containing the HTTP headers */
329 const char *headers;
331
332/** Entry for handling an HTTP GET request.
333 *
334 * This entry matches a request if "string" is equal to the requested
335 * resource, or if "is_prefix" is true and "string" is a prefix of the
336 * requested resource.
337 *
338 * The 'handler' function is called to handle the request. It receives
339 * an arguments structure, and must return 0 on success or -1 if we should
340 * close the connection.
341 **/
342typedef struct url_table_ent_t {
343 const char *string;
344 int is_prefix;
345 int (*handler)(dir_connection_t *conn, const get_handler_args_t *args);
347
349 const get_handler_args_t *args);
351 const get_handler_args_t *args);
353 const get_handler_args_t *args);
355 const get_handler_args_t *args);
357 const get_handler_args_t *args);
358static int handle_get_keys(dir_connection_t *conn,
359 const get_handler_args_t *args);
360static int handle_get_robots(dir_connection_t *conn,
361 const get_handler_args_t *args);
363 const get_handler_args_t *args);
365 const get_handler_args_t *args);
366
367/** Table for handling GET requests. */
368static const url_table_ent_t url_table[] = {
369 { "/tor/", 0, handle_get_frontpage },
370 { "/tor/status-vote/current/consensus", 1, handle_get_current_consensus },
371 { "/tor/status-vote/current/", 1, handle_get_status_vote },
372 { "/tor/status-vote/next/bandwidth", 0, handle_get_next_bandwidth },
373 { "/tor/status-vote/next/", 1, handle_get_status_vote },
374 { "/tor/micro/d/", 1, handle_get_microdesc },
375 { "/tor/server/", 1, handle_get_descriptor },
376 { "/tor/extra/", 1, handle_get_descriptor },
377 { "/tor/keys/", 1, handle_get_keys },
378 { "/tor/hs/3/", 1, handle_get_hs_descriptor_v3 },
379 { "/tor/robots.txt", 0, handle_get_robots },
380 { "/tor/networkstatus-bridges", 0, handle_get_networkstatus_bridges },
381 { NULL, 0, NULL },
382};
383
384/** Helper function: called when a dirserver gets a complete HTTP GET
385 * request. Look for a request for a directory or for a rendezvous
386 * service descriptor. On finding one, write a response into
387 * conn->outbuf. If the request is unrecognized, send a 404.
388 * Return 0 if we handled this successfully, or -1 if we need to close
389 * the connection. */
390MOCK_IMPL(STATIC int,
391directory_handle_command_get,(dir_connection_t *conn, const char *headers,
392 const char *req_body, size_t req_body_len))
393{
394 char *url, *url_mem, *header;
395 time_t if_modified_since = 0;
396 int zlib_compressed_in_url;
397 unsigned compression_methods_supported;
398
399 /* We ignore the body of a GET request. */
400 (void)req_body;
401 (void)req_body_len;
402
403 log_debug(LD_DIRSERV,"Received GET command.");
404
406
407 if (parse_http_url(headers, &url) < 0) {
408 write_short_http_response(conn, 400, "Bad request");
409 return 0;
410 }
411 if ((header = http_get_header(headers, "If-Modified-Since: "))) {
412 struct tm tm;
413 if (parse_http_time(header, &tm) == 0) {
414 if (tor_timegm(&tm, &if_modified_since)<0) {
415 if_modified_since = 0;
416 } else {
417 log_debug(LD_DIRSERV, "If-Modified-Since is '%s'.", escaped(header));
418 }
419 }
420 /* The correct behavior on a malformed If-Modified-Since header is to
421 * act as if no If-Modified-Since header had been given. */
422 tor_free(header);
423 }
424 log_debug(LD_DIRSERV,"rewritten url as '%s'.", escaped(url));
425
426 url_mem = url;
427 {
428 size_t url_len = strlen(url);
429
430 zlib_compressed_in_url = url_len > 2 && !strcmp(url+url_len-2, ".z");
431 if (zlib_compressed_in_url) {
432 url[url_len-2] = '\0';
433 }
434 }
435
436 if ((header = http_get_header(headers, "Accept-Encoding: "))) {
437 compression_methods_supported = parse_accept_encoding_header(header);
438 tor_free(header);
439 } else {
440 compression_methods_supported = (1u << NO_METHOD);
441 }
442 if (zlib_compressed_in_url) {
443 compression_methods_supported |= (1u << ZLIB_METHOD);
444 }
445
446 /* Remove all methods that we don't both support. */
447 compression_methods_supported &= tor_compress_get_supported_method_bitmask();
448
450 args.url = url;
451 args.headers = headers;
452 args.if_modified_since = if_modified_since;
453 args.compression_supported = compression_methods_supported;
454
455 int i, result = -1;
456 for (i = 0; url_table[i].string; ++i) {
457 int match;
458 if (url_table[i].is_prefix) {
459 match = !strcmpstart(url, url_table[i].string);
460 } else {
461 match = !strcmp(url, url_table[i].string);
462 }
463 if (match) {
464 result = url_table[i].handler(conn, &args);
465 goto done;
466 }
467 }
468
469 /* we didn't recognize the url */
470 write_short_http_response(conn, 404, "Not found");
471 result = 0;
472
473 done:
474 tor_free(url_mem);
475 return result;
476}
477
478/** Helper function for GET / or GET /tor/
479 */
480static int
482{
483 (void) args; /* unused */
484 const char *frontpage = relay_get_dirportfrontpage();
485
486 if (frontpage) {
487 size_t dlen;
488 dlen = strlen(frontpage);
489 /* Let's return a disclaimer page (users shouldn't use V1 anymore,
490 and caches don't fetch '/', so this is safe). */
491
492 /* [We don't check for write_bucket_low here, since we want to serve
493 * this page no matter what.] */
494 write_http_response_header_impl(conn, dlen, "text/html", "identity",
495 NULL, DIRPORTFRONTPAGE_CACHE_LIFETIME);
496 connection_buf_add(frontpage, dlen, TO_CONN(conn));
497 } else {
498 write_short_http_response(conn, 404, "Not found");
499 }
500 return 0;
501}
502
503/** Warn that the cached consensus <b>consensus</b> of type
504 * <b>flavor</b> too new or too old, based on <b>is_too_new</b>,
505 * and will not be served to clients. Rate-limit the warning to avoid logging
506 * an entry on every request.
507 */
508static void
510 const struct consensus_cache_entry_t *consensus,
511 const char *flavor, time_t now, bool is_too_new)
512{
513#define NOT_REASONABLY_LIVE_WARNING_INTERVAL (60*60)
514 static ratelim_t warned[2] = { RATELIM_INIT(
515 NOT_REASONABLY_LIVE_WARNING_INTERVAL),
516 RATELIM_INIT(
517 NOT_REASONABLY_LIVE_WARNING_INTERVAL) };
518 char timestamp[ISO_TIME_LEN+1];
519 /* valid_after if is_too_new, valid_until if !is_too_new */
520 time_t valid_time = 0;
521 char *dupes = NULL;
522
523 if (is_too_new) {
524 if (consensus_cache_entry_get_valid_after(consensus, &valid_time))
525 return;
526 dupes = rate_limit_log(&warned[1], now);
527 } else {
528 if (consensus_cache_entry_get_valid_until(consensus, &valid_time))
529 return;
530 dupes = rate_limit_log(&warned[0], now);
531 }
532
533 if (dupes) {
534 format_local_iso_time(timestamp, valid_time);
535 log_warn(LD_DIRSERV, "Our %s%sconsensus is too %s, so we will not "
536 "serve it to clients. It was valid %s %s local time and we "
537 "continued to serve it for up to 24 hours %s.%s",
538 flavor ? flavor : "",
539 flavor ? " " : "",
540 is_too_new ? "new" : "old",
541 is_too_new ? "after" : "until",
542 timestamp,
543 is_too_new ? "before it was valid" : "after it expired",
544 dupes);
545 tor_free(dupes);
546 }
547}
548
549/**
550 * Parse a single hex-encoded sha3-256 digest from <b>hex</b> into
551 * <b>digest</b>. Return 0 on success. On failure, report that the hash came
552 * from <b>location</b>, report that we are taking <b>action</b> with it, and
553 * return -1.
554 */
555static int
556parse_one_diff_hash(uint8_t *digest, const char *hex, const char *location,
557 const char *action)
558{
559 if (base16_decode((char*)digest, DIGEST256_LEN, hex, strlen(hex)) ==
561 return 0;
562 } else {
563 log_fn(LOG_PROTOCOL_WARN, LD_DIR,
564 "%s contained bogus digest %s; %s.",
565 location, escaped(hex), action);
566 return -1;
567 }
568}
569
570/** If there is an X-Or-Diff-From-Consensus header included in <b>headers</b>,
571 * set <b>digest_out</b> to a new smartlist containing every 256-bit
572 * hex-encoded digest listed in that header and return 0. Otherwise return
573 * -1. */
574static int
575parse_or_diff_from_header(smartlist_t **digests_out, const char *headers)
576{
577 char *hdr = http_get_header(headers, X_OR_DIFF_FROM_CONSENSUS_HEADER);
578 if (hdr == NULL) {
579 return -1;
580 }
581 smartlist_t *hex_digests = smartlist_new();
582 *digests_out = smartlist_new();
583 smartlist_split_string(hex_digests, hdr, " ",
584 SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
585 SMARTLIST_FOREACH_BEGIN(hex_digests, const char *, hex) {
586 uint8_t digest[DIGEST256_LEN];
587 if (!parse_one_diff_hash(digest, hex, "X-Or-Diff-From-Consensus header",
588 "ignoring")) {
589 smartlist_add(*digests_out, tor_memdup(digest, sizeof(digest)));
590 }
591 } SMARTLIST_FOREACH_END(hex);
592 SMARTLIST_FOREACH(hex_digests, char *, cp, tor_free(cp));
593 smartlist_free(hex_digests);
594 tor_free(hdr);
595 return 0;
596}
597
598/** Fallback compression method. The fallback compression method is used in
599 * case a client requests a non-compressed document. We only store compressed
600 * documents, so we use this compression method to fetch the document and let
601 * the spooling system do the streaming decompression.
602 */
603#define FALLBACK_COMPRESS_METHOD ZLIB_METHOD
604
605/**
606 * Try to find the best consensus diff possible in order to serve a client
607 * request for a diff from one of the consensuses in <b>digests</b> to the
608 * current consensus of flavor <b>flav</b>. The client supports the
609 * compression methods listed in the <b>compression_methods</b> bitfield:
610 * place the method chosen (if any) into <b>compression_used_out</b>.
611 */
612static struct consensus_cache_entry_t *
613find_best_diff(const smartlist_t *digests, int flav,
614 unsigned compression_methods,
615 compress_method_t *compression_used_out)
616{
617 struct consensus_cache_entry_t *result = NULL;
618
619 SMARTLIST_FOREACH_BEGIN(digests, const uint8_t *, diff_from) {
620 unsigned u;
621 for (u = 0; u < ARRAY_LENGTH(srv_meth_pref_precompressed); ++u) {
623 if (0 == (compression_methods & (1u<<method)))
624 continue; // client doesn't like this one, or we don't have it.
625 if (consdiffmgr_find_diff_from(&result, flav, DIGEST_SHA3_256,
626 diff_from, DIGEST256_LEN,
627 method) == CONSDIFF_AVAILABLE) {
628 tor_assert_nonfatal(result);
629 *compression_used_out = method;
630 return result;
631 }
632 }
633 } SMARTLIST_FOREACH_END(diff_from);
634
635 SMARTLIST_FOREACH_BEGIN(digests, const uint8_t *, diff_from) {
636 if (consdiffmgr_find_diff_from(&result, flav, DIGEST_SHA3_256, diff_from,
637 DIGEST256_LEN, FALLBACK_COMPRESS_METHOD) == CONSDIFF_AVAILABLE) {
638 tor_assert_nonfatal(result);
639 *compression_used_out = FALLBACK_COMPRESS_METHOD;
640 return result;
641 }
642 } SMARTLIST_FOREACH_END(diff_from);
643
644 return NULL;
645}
646
647/** Lookup the cached consensus document by the flavor found in <b>flav</b>.
648 * The preferred set of compression methods should be listed in the
649 * <b>compression_methods</b> bitfield. The compression method chosen (if any)
650 * is stored in <b>compression_used_out</b>. */
651static struct consensus_cache_entry_t *
653 unsigned compression_methods,
654 compress_method_t *compression_used_out)
655{
656 struct consensus_cache_entry_t *result = NULL;
657 unsigned u;
658
659 for (u = 0; u < ARRAY_LENGTH(srv_meth_pref_precompressed); ++u) {
661
662 if (0 == (compression_methods & (1u<<method)))
663 continue;
664
665 if (consdiffmgr_find_consensus(&result, flav,
666 method) == CONSDIFF_AVAILABLE) {
667 tor_assert_nonfatal(result);
668 *compression_used_out = method;
669 return result;
670 }
671 }
672
673 if (consdiffmgr_find_consensus(&result, flav,
674 FALLBACK_COMPRESS_METHOD) == CONSDIFF_AVAILABLE) {
675 tor_assert_nonfatal(result);
676 *compression_used_out = FALLBACK_COMPRESS_METHOD;
677 return result;
678 }
679
680 return NULL;
681}
682
683/** Try to find the best supported compression method possible from a given
684 * <b>compression_methods</b>. Return NO_METHOD if no mutually supported
685 * compression method could be found. */
687find_best_compression_method(unsigned compression_methods, int stream)
688{
689 unsigned u;
690 compress_method_t *methods;
691 size_t length;
692
693 if (stream) {
696 } else {
699 }
700
701 for (u = 0; u < length; ++u) {
702 compress_method_t method = methods[u];
703 if (compression_methods & (1u<<method))
704 return method;
705 }
706
707 return NO_METHOD;
708}
709
710/** Check if any of the digests in <b>digests</b> matches the latest consensus
711 * flavor (given in <b>flavor</b>) that we have available. */
712static int
714 const smartlist_t *digests)
715{
716 const networkstatus_t *ns = NULL;
717
718 if (digests == NULL)
719 return 0;
720
722
723 if (ns == NULL)
724 return 0;
725
726 SMARTLIST_FOREACH_BEGIN(digests, const uint8_t *, digest) {
728 return 1;
729 } SMARTLIST_FOREACH_END(digest);
730
731 return 0;
732}
733
734/** Encodes the results of parsing a consensus request to figure out what
735 * consensus, and possibly what diffs, the user asked for. */
736typedef struct {
737 /** name of the flavor to retrieve. */
738 char *flavor;
739 /** flavor to retrieve, as enum. */
741 /** plus-separated list of authority fingerprints; see
742 * client_likes_consensus(). Aliases the URL in the request passed to
743 * parse_consensus_request(). */
744 const char *want_fps;
745 /** Optionally, a smartlist of sha3 digests-as-signed of the consensuses
746 * to return a diff from. */
748 /** If true, never send a full consensus. If there is no diff, send
749 * a 404 instead. */
752
753/** Remove all data held in <b>req</b>. Do not free <b>req</b> itself, since
754 * it is stack-allocated. */
755static void
757{
758 if (!req)
759 return;
760 tor_free(req->flavor);
761 if (req->diff_from_digests) {
762 SMARTLIST_FOREACH(req->diff_from_digests, uint8_t *, d, tor_free(d));
763 smartlist_free(req->diff_from_digests);
764 }
765 memset(req, 0, sizeof(parsed_consensus_request_t));
766}
767
768/**
769 * Parse the URL and relevant headers of <b>args</b> for a current-consensus
770 * request to learn what flavor of consensus we want, what keys it must be
771 * signed with, and what diffs we would accept (or demand) instead. Return 0
772 * on success and -1 on failure.
773 */
774static int
776 const get_handler_args_t *args)
777{
778 const char *url = args->url;
779 memset(out, 0, sizeof(parsed_consensus_request_t));
780 out->flav = FLAV_NS;
781
782 const char CONSENSUS_URL_PREFIX[] = "/tor/status-vote/current/consensus/";
783 const char CONSENSUS_FLAVORED_PREFIX[] =
784 "/tor/status-vote/current/consensus-";
785
786 /* figure out the flavor if any, and who we wanted to sign the thing */
787 const char *after_flavor = NULL;
788
789 if (!strcmpstart(url, CONSENSUS_FLAVORED_PREFIX)) {
790 const char *f, *cp;
791 f = url + strlen(CONSENSUS_FLAVORED_PREFIX);
792 cp = strchr(f, '/');
793 if (cp) {
794 after_flavor = cp+1;
795 out->flavor = tor_strndup(f, cp-f);
796 } else {
797 out->flavor = tor_strdup(f);
798 }
800 if (flav < 0)
801 flav = FLAV_NS;
802 out->flav = flav;
803 } else {
804 if (!strcmpstart(url, CONSENSUS_URL_PREFIX))
805 after_flavor = url+strlen(CONSENSUS_URL_PREFIX);
806 }
807
808 /* see whether we've been asked explicitly for a diff from an older
809 * consensus. (The user might also have said that a diff would be okay,
810 * via X-Or-Diff-From-Consensus */
811 const char DIFF_COMPONENT[] = "diff/";
812 char *diff_hash_in_url = NULL;
813 if (after_flavor && !strcmpstart(after_flavor, DIFF_COMPONENT)) {
814 after_flavor += strlen(DIFF_COMPONENT);
815 const char *cp = strchr(after_flavor, '/');
816 if (cp) {
817 diff_hash_in_url = tor_strndup(after_flavor, cp-after_flavor);
818 out->want_fps = cp+1;
819 } else {
820 diff_hash_in_url = tor_strdup(after_flavor);
821 out->want_fps = NULL;
822 }
823 } else {
824 out->want_fps = after_flavor;
825 }
826
827 if (diff_hash_in_url) {
828 uint8_t diff_from[DIGEST256_LEN];
830 out->diff_only = 1;
831 int ok = !parse_one_diff_hash(diff_from, diff_hash_in_url, "URL",
832 "rejecting");
833 tor_free(diff_hash_in_url);
834 if (ok) {
836 tor_memdup(diff_from, DIGEST256_LEN));
837 } else {
838 return -1;
839 }
840 } else {
842 }
843
844 return 0;
845}
846
847/** Helper function for GET /tor/status-vote/current/consensus
848 */
849static int
851 const get_handler_args_t *args)
852{
853 const compress_method_t compress_method =
855 const time_t if_modified_since = args->if_modified_since;
856 int clear_spool = 0;
857
858 /* v3 network status fetch. */
859 long lifetime = NETWORKSTATUS_CACHE_LIFETIME;
860
861 time_t now = time(NULL);
863
864 if (parse_consensus_request(&req, args) < 0) {
865 write_short_http_response(conn, 404, "Couldn't parse request");
866 goto done;
867 }
868
870 req.diff_from_digests)) {
871 write_short_http_response(conn, 304, "Not modified");
873 goto done;
874 }
875
876 struct consensus_cache_entry_t *cached_consensus = NULL;
877
878 compress_method_t compression_used = NO_METHOD;
879 if (req.diff_from_digests) {
880 cached_consensus = find_best_diff(req.diff_from_digests, req.flav,
882 &compression_used);
883 }
884
885 if (req.diff_only && !cached_consensus) {
886 write_short_http_response(conn, 404, "No such diff available");
888 goto done;
889 }
890
891 if (! cached_consensus) {
892 cached_consensus = find_best_consensus(req.flav,
894 &compression_used);
895 }
896
897 time_t valid_after, fresh_until, valid_until;
898 int have_valid_after = 0, have_fresh_until = 0, have_valid_until = 0;
899 if (cached_consensus) {
900 have_valid_after =
901 !consensus_cache_entry_get_valid_after(cached_consensus, &valid_after);
902 have_fresh_until =
903 !consensus_cache_entry_get_fresh_until(cached_consensus, &fresh_until);
904 have_valid_until =
905 !consensus_cache_entry_get_valid_until(cached_consensus, &valid_until);
906 }
907
908 if (cached_consensus && have_valid_after &&
910 write_short_http_response(conn, 404, "Consensus is too new");
911 warn_consensus_is_not_reasonably_live(cached_consensus, req.flavor, now,
912 1);
914 goto done;
915 } else if (
916 cached_consensus && have_valid_until &&
918 write_short_http_response(conn, 404, "Consensus is too old");
919 warn_consensus_is_not_reasonably_live(cached_consensus, req.flavor, now,
920 0);
922 goto done;
923 }
924
925 if (cached_consensus && req.want_fps &&
926 !client_likes_consensus(cached_consensus, req.want_fps)) {
927 write_short_http_response(conn, 404, "Consensus not signed by sufficient "
928 "number of requested authorities");
930 goto done;
931 }
932
933 conn->spool = smartlist_new();
934 clear_spool = 1;
935 {
936 spooled_resource_t *spooled;
937 if (cached_consensus) {
938 spooled = spooled_resource_new_from_cache_entry(cached_consensus);
939 smartlist_add(conn->spool, spooled);
940 }
941 }
942
943 lifetime = (have_fresh_until && fresh_until > now) ? fresh_until - now : 0;
944
945 size_t size_guess = 0;
946 int n_expired = 0;
947 dirserv_spool_remove_missing_and_guess_size(conn, if_modified_since,
948 compress_method != NO_METHOD,
949 &size_guess,
950 &n_expired);
951
952 if (!smartlist_len(conn->spool) && !n_expired) {
953 write_short_http_response(conn, 404, "Not found");
955 goto done;
956 } else if (!smartlist_len(conn->spool)) {
957 write_short_http_response(conn, 304, "Not modified");
959 goto done;
960 }
961
962 if (connection_dir_is_global_write_low(TO_CONN(conn), size_guess)) {
963 log_debug(LD_DIRSERV,
964 "Client asked for network status lists, but we've been "
965 "writing too many bytes lately. Sending 503 Dir busy.");
966 write_short_http_response(conn, 503, "Directory busy, try again later");
968 goto done;
969 }
970
971 tor_addr_t addr;
972 if (tor_addr_parse(&addr, (TO_CONN(conn))->address) >= 0) {
974 &addr, NULL,
975 time(NULL));
977 /* Note that a request for a network status has started, so that we
978 * can measure the download time later on. */
979 if (conn->dirreq_id)
980 geoip_start_dirreq(conn->dirreq_id, size_guess, DIRREQ_TUNNELED);
981 else
982 geoip_start_dirreq(TO_CONN(conn)->global_identifier, size_guess,
983 DIRREQ_DIRECT);
984 }
985
986 /* Use this header to tell caches that the response depends on the
987 * X-Or-Diff-From-Consensus header (or lack thereof). */
988 const char vary_header[] = "Vary: X-Or-Diff-From-Consensus\r\n";
989
990 clear_spool = 0;
991
992 // The compress_method might have been NO_METHOD, but we store the data
993 // compressed. Decompress them using `compression_used`. See fallback code in
994 // find_best_consensus() and find_best_diff().
996 compress_method == NO_METHOD ?
997 NO_METHOD : compression_used,
998 vary_header,
999 smartlist_len(conn->spool) == 1 ? lifetime : 0);
1000
1001 if (compress_method == NO_METHOD && smartlist_len(conn->spool))
1002 conn->compress_state = tor_compress_new(0, compression_used,
1003 HIGH_COMPRESSION);
1004
1005 /* Prime the connection with some data. */
1006 const int initial_flush_result = connection_dirserv_flushed_some(conn);
1007 tor_assert_nonfatal(initial_flush_result == 0);
1008 goto done;
1009
1010 done:
1012 if (clear_spool) {
1013 dir_conn_clear_spool(conn);
1014 }
1015 return 0;
1016}
1017
1018/** Helper function for GET /tor/status-vote/{current,next}/...
1019 */
1020static int
1022{
1023 const char *url = args->url;
1024 {
1025 ssize_t body_len = 0;
1026 ssize_t estimated_len = 0;
1027 int lifetime = 60; /* XXXX?? should actually use vote intervals. */
1028 /* This smartlist holds strings that we can compress on the fly. */
1029 smartlist_t *items = smartlist_new();
1030 /* This smartlist holds cached_dir_t objects that have a precompressed
1031 * deflated version. */
1032 smartlist_t *dir_items = smartlist_new();
1033 dirvote_dirreq_get_status_vote(url, items, dir_items);
1034 if (!smartlist_len(dir_items) && !smartlist_len(items)) {
1035 write_short_http_response(conn, 404, "Not found");
1036 goto vote_done;
1037 }
1038
1039 /* We're sending items from at most one kind of source */
1040 tor_assert_nonfatal(smartlist_len(items) == 0 ||
1041 smartlist_len(dir_items) == 0);
1042
1043 int streaming;
1044 unsigned mask;
1045 if (smartlist_len(items)) {
1046 /* We're taking strings and compressing them on the fly. */
1047 streaming = 1;
1048 mask = ~0u;
1049 } else {
1050 /* We're taking cached_dir_t objects. We only have them uncompressed
1051 * or deflated. */
1052 streaming = 0;
1053 mask = (1u<<NO_METHOD) | (1u<<ZLIB_METHOD);
1054 }
1055 const compress_method_t compress_method = find_best_compression_method(
1056 args->compression_supported&mask, streaming);
1057
1058 SMARTLIST_FOREACH(dir_items, cached_dir_t *, d,
1059 body_len += compress_method != NO_METHOD ?
1060 d->dir_compressed_len : d->dir_len);
1061 estimated_len += body_len;
1062 SMARTLIST_FOREACH(items, const char *, item, {
1063 size_t ln = strlen(item);
1064 if (compress_method != NO_METHOD) {
1065 estimated_len += ln/2;
1066 } else {
1067 body_len += ln; estimated_len += ln;
1068 }
1069 });
1070
1071 if (connection_dir_is_global_write_low(TO_CONN(conn), estimated_len)) {
1072 write_short_http_response(conn, 503, "Directory busy, try again later");
1073 goto vote_done;
1074 }
1075 write_http_response_header(conn, body_len ? body_len : -1,
1076 compress_method,
1077 lifetime);
1078
1079 if (smartlist_len(items)) {
1080 if (compress_method != NO_METHOD) {
1081 conn->compress_state = tor_compress_new(1, compress_method,
1083 }
1084
1085 SMARTLIST_FOREACH(items, const char *, c,
1086 connection_dir_buf_add(c, strlen(c), conn,
1087 c_sl_idx == c_sl_len - 1));
1088 } else {
1089 SMARTLIST_FOREACH(dir_items, cached_dir_t *, d,
1090 connection_buf_add(compress_method != NO_METHOD ?
1091 d->dir_compressed : d->dir,
1092 compress_method != NO_METHOD ?
1093 d->dir_compressed_len : d->dir_len,
1094 TO_CONN(conn)));
1095 }
1096 vote_done:
1097 smartlist_free(items);
1098 smartlist_free(dir_items);
1099 goto done;
1100 }
1101 done:
1102 return 0;
1103}
1104
1105/** Helper function for GET /tor/micro/d/...
1106 */
1107static int
1109{
1110 const char *url = args->url;
1111 const compress_method_t compress_method =
1113 int clear_spool = 1;
1114 {
1115 conn->spool = smartlist_new();
1116
1117 dir_split_resource_into_spoolable(url+strlen("/tor/micro/d/"),
1118 DIR_SPOOL_MICRODESC,
1119 conn->spool, NULL,
1120 DSR_DIGEST256|DSR_BASE64|DSR_SORT_UNIQ);
1121
1122 size_t size_guess = 0;
1124 compress_method != NO_METHOD,
1125 &size_guess, NULL);
1126 if (smartlist_len(conn->spool) == 0) {
1127 write_short_http_response(conn, 404, "Not found");
1128 goto done;
1129 }
1130 if (connection_dir_is_global_write_low(TO_CONN(conn), size_guess)) {
1131 log_info(LD_DIRSERV,
1132 "Client asked for server descriptors, but we've been "
1133 "writing too many bytes lately. Sending 503 Dir busy.");
1134 write_short_http_response(conn, 503, "Directory busy, try again later");
1135 goto done;
1136 }
1137
1138 clear_spool = 0;
1140 compress_method,
1141 MICRODESC_CACHE_LIFETIME);
1142
1143 if (compress_method != NO_METHOD)
1144 conn->compress_state = tor_compress_new(1, compress_method,
1146
1147 const int initial_flush_result = connection_dirserv_flushed_some(conn);
1148 tor_assert_nonfatal(initial_flush_result == 0);
1149 goto done;
1150 }
1151
1152 done:
1153 if (clear_spool) {
1154 dir_conn_clear_spool(conn);
1155 }
1156 return 0;
1157}
1158
1159/** Helper function for GET /tor/{server,extra}/...
1160 */
1161static int
1163{
1164 const char *url = args->url;
1165 const compress_method_t compress_method =
1167 const or_options_t *options = get_options();
1168 int clear_spool = 1;
1169 if (!strcmpstart(url,"/tor/server/") ||
1170 (!options->BridgeAuthoritativeDir &&
1171 !options->BridgeRelay && !strcmpstart(url,"/tor/extra/"))) {
1172 int res;
1173 const char *msg = NULL;
1174 int cache_lifetime = 0;
1175 int is_extra = !strcmpstart(url,"/tor/extra/");
1176 url += is_extra ? strlen("/tor/extra/") : strlen("/tor/server/");
1177 dir_spool_source_t source;
1178 time_t publish_cutoff = 0;
1179 if (!strcmpstart(url, "d/")) {
1180 source =
1181 is_extra ? DIR_SPOOL_EXTRA_BY_DIGEST : DIR_SPOOL_SERVER_BY_DIGEST;
1182 } else {
1183 source =
1184 is_extra ? DIR_SPOOL_EXTRA_BY_FP : DIR_SPOOL_SERVER_BY_FP;
1185 /* We only want to apply a publish cutoff when we're requesting
1186 * resources by fingerprint. */
1187 publish_cutoff = time(NULL) - ROUTER_MAX_AGE_TO_PUBLISH;
1188 }
1189
1190 conn->spool = smartlist_new();
1191 res = dirserv_get_routerdesc_spool(conn->spool, url,
1192 source,
1194 &msg);
1195
1196 if (!strcmpstart(url, "all")) {
1197 cache_lifetime = FULL_DIR_CACHE_LIFETIME;
1198 } else if (smartlist_len(conn->spool) == 1) {
1199 cache_lifetime = ROUTERDESC_BY_DIGEST_CACHE_LIFETIME;
1200 }
1201
1202 size_t size_guess = 0;
1203 int n_expired = 0;
1205 compress_method != NO_METHOD,
1206 &size_guess, &n_expired);
1207
1208 /* If we are the bridge authority and the descriptor is a bridge
1209 * descriptor, remember that we served this descriptor for desc stats. */
1210 /* XXXX it's a bit of a kludge to have this here. */
1211 if (get_options()->BridgeAuthoritativeDir &&
1212 source == DIR_SPOOL_SERVER_BY_FP) {
1214 const routerinfo_t *router =
1215 router_get_by_id_digest((const char *)spooled->digest);
1216 /* router can be NULL here when the bridge auth is asked for its own
1217 * descriptor. */
1218 if (router && router->purpose == ROUTER_PURPOSE_BRIDGE)
1219 rep_hist_note_desc_served(router->cache_info.identity_digest);
1220 } SMARTLIST_FOREACH_END(spooled);
1221 }
1222
1223 if (res < 0 || size_guess == 0 || smartlist_len(conn->spool) == 0) {
1224 if (msg == NULL)
1225 msg = "Not found";
1226 write_short_http_response(conn, 404, msg);
1227 } else {
1228 if (connection_dir_is_global_write_low(TO_CONN(conn), size_guess)) {
1229 log_info(LD_DIRSERV,
1230 "Client asked for server descriptors, but we've been "
1231 "writing too many bytes lately. Sending 503 Dir busy.");
1232 write_short_http_response(conn, 503,
1233 "Directory busy, try again later");
1234 dir_conn_clear_spool(conn);
1235 goto done;
1236 }
1237 write_http_response_header(conn, -1, compress_method, cache_lifetime);
1238 if (compress_method != NO_METHOD)
1239 conn->compress_state = tor_compress_new(1, compress_method,
1241 clear_spool = 0;
1242 /* Prime the connection with some data. */
1243 int initial_flush_result = connection_dirserv_flushed_some(conn);
1244 tor_assert_nonfatal(initial_flush_result == 0);
1245 }
1246 goto done;
1247 }
1248 done:
1249 if (clear_spool)
1250 dir_conn_clear_spool(conn);
1251 return 0;
1252}
1253
1254/** Helper function for GET /tor/keys/...
1255 */
1256static int
1258{
1259 const char *url = args->url;
1260 const compress_method_t compress_method =
1262 const time_t if_modified_since = args->if_modified_since;
1263 {
1264 smartlist_t *certs = smartlist_new();
1265 ssize_t len = -1;
1266 if (!strcmp(url, "/tor/keys/all")) {
1268 } else if (!strcmp(url, "/tor/keys/authority")) {
1270 if (cert)
1271 smartlist_add(certs, cert);
1272 } else if (!strcmpstart(url, "/tor/keys/fp/")) {
1273 smartlist_t *fps = smartlist_new();
1274 dir_split_resource_into_fingerprints(url+strlen("/tor/keys/fp/"),
1275 fps, NULL,
1276 DSR_HEX|DSR_SORT_UNIQ);
1277 SMARTLIST_FOREACH(fps, char *, d, {
1279 if (c) smartlist_add(certs, c);
1280 tor_free(d);
1281 });
1282 smartlist_free(fps);
1283 } else if (!strcmpstart(url, "/tor/keys/sk/")) {
1284 smartlist_t *fps = smartlist_new();
1285 dir_split_resource_into_fingerprints(url+strlen("/tor/keys/sk/"),
1286 fps, NULL,
1287 DSR_HEX|DSR_SORT_UNIQ);
1288 SMARTLIST_FOREACH(fps, char *, d, {
1290 if (c) smartlist_add(certs, c);
1291 tor_free(d);
1292 });
1293 smartlist_free(fps);
1294 } else if (!strcmpstart(url, "/tor/keys/fp-sk/")) {
1295 smartlist_t *fp_sks = smartlist_new();
1296 dir_split_resource_into_fingerprint_pairs(url+strlen("/tor/keys/fp-sk/"),
1297 fp_sks);
1298 SMARTLIST_FOREACH(fp_sks, fp_pair_t *, pair, {
1300 pair->second);
1301 if (c) smartlist_add(certs, c);
1302 tor_free(pair);
1303 });
1304 smartlist_free(fp_sks);
1305 } else {
1306 write_short_http_response(conn, 400, "Bad request");
1307 goto keys_done;
1308 }
1309 if (!smartlist_len(certs)) {
1310 write_short_http_response(conn, 404, "Not found");
1311 goto keys_done;
1312 }
1314 if (c->cache_info.published_on < if_modified_since)
1315 SMARTLIST_DEL_CURRENT(certs, c));
1316 if (!smartlist_len(certs)) {
1317 write_short_http_response(conn, 304, "Not modified");
1318 goto keys_done;
1319 }
1320 len = 0;
1323
1325 compress_method != NO_METHOD ? len/2 : len)) {
1326 write_short_http_response(conn, 503, "Directory busy, try again later");
1327 goto keys_done;
1328 }
1329
1331 compress_method != NO_METHOD ? -1 : len,
1332 compress_method,
1333 60*60);
1334 if (compress_method != NO_METHOD) {
1335 conn->compress_state = tor_compress_new(1, compress_method,
1337 }
1338
1340 connection_dir_buf_add(c->cache_info.signed_descriptor_body,
1341 c->cache_info.signed_descriptor_len,
1342 conn, c_sl_idx == c_sl_len - 1));
1343 keys_done:
1344 smartlist_free(certs);
1345 goto done;
1346 }
1347 done:
1348 return 0;
1349}
1350
1351/** Helper function for GET `/tor/hs/3/...`. Only for version 3.
1352 */
1353STATIC int
1355 const get_handler_args_t *args)
1356{
1357 int retval;
1358 const char *desc_str = NULL;
1359 const char *pubkey_str = NULL;
1360 const char *url = args->url;
1361
1362 /* Reject non anonymous dir connections (which also tests if encrypted). We
1363 * do not allow single hop clients to query an HSDir. */
1364 if (!connection_dir_is_anonymous(conn)) {
1365 write_short_http_response(conn, 503,
1366 "Rejecting single hop HS v3 descriptor request");
1367 goto done;
1368 }
1369
1370 /* After the path prefix follows the base64 encoded blinded pubkey which we
1371 * use to get the descriptor from the cache. Skip the prefix and get the
1372 * pubkey. */
1373 tor_assert(!strcmpstart(url, "/tor/hs/3/"));
1374 pubkey_str = url + strlen("/tor/hs/3/");
1376 pubkey_str, &desc_str);
1377 if (retval <= 0 || desc_str == NULL) {
1378 write_short_http_response(conn, 404, "Not found");
1379 goto done;
1380 }
1381
1382 /* Found requested descriptor! Pass it to this nice client. */
1383 write_http_response_header(conn, strlen(desc_str), NO_METHOD, 0);
1384 connection_buf_add(desc_str, strlen(desc_str), TO_CONN(conn));
1385
1386 /* We have successfully written the descriptor on the connection outbuf so
1387 * save this query identifier into the dir_connection_t in order
1388 * to associate it to the descriptor when closing. */
1389 {
1390 /* Decode blinded key. This is certain to work else
1391 * hs_cache_lookup_as_dir() would have failed. */
1392 ed25519_public_key_t blinded_key;
1393 ed25519_public_from_base64(&blinded_key, pubkey_str);
1394 conn->hs_ident = hs_ident_server_dir_conn_new(&blinded_key);
1395 }
1396
1397 done:
1398 return 0;
1399}
1400
1401/** Helper function for GET /tor/networkstatus-bridges
1402 */
1403static int
1405 const get_handler_args_t *args)
1406{
1407 const char *headers = args->headers;
1408
1409 const or_options_t *options = get_options();
1410 if (options->BridgeAuthoritativeDir &&
1411 options->BridgePassword_AuthDigest_ &&
1413 char *status;
1414 char digest[DIGEST256_LEN];
1415
1416 char *header = http_get_header(headers, "Authorization: Basic ");
1417 if (header)
1418 crypto_digest256(digest, header, strlen(header), DIGEST_SHA256);
1419
1420 /* now make sure the password is there and right */
1421 if (!header ||
1422 tor_memneq(digest,
1424 write_short_http_response(conn, 404, "Not found");
1425 tor_free(header);
1426 goto done;
1427 }
1428 tor_free(header);
1429
1430 /* all happy now. send an answer. */
1431 status = networkstatus_getinfo_by_purpose("bridge", time(NULL));
1432 size_t dlen = strlen(status);
1433 write_http_response_header(conn, dlen, NO_METHOD, 0);
1434 connection_buf_add(status, dlen, TO_CONN(conn));
1435 tor_free(status);
1436 goto done;
1437 }
1438 done:
1439 return 0;
1440}
1441
1442/** Helper function for GET the bandwidth file used for the next vote */
1443static int
1445 const get_handler_args_t *args)
1446{
1447 log_debug(LD_DIR, "Getting next bandwidth.");
1448 const or_options_t *options = get_options();
1449 const compress_method_t compress_method =
1451
1452 if (options->V3BandwidthsFile) {
1453 char *bandwidth = read_file_to_str(options->V3BandwidthsFile,
1454 RFTS_IGNORE_MISSING, NULL);
1455 if (bandwidth != NULL) {
1456 ssize_t len = strlen(bandwidth);
1457 write_http_response_header(conn, compress_method != NO_METHOD ? -1 : len,
1458 compress_method, BANDWIDTH_CACHE_LIFETIME);
1459 if (compress_method != NO_METHOD) {
1460 conn->compress_state = tor_compress_new(1, compress_method,
1462 log_debug(LD_DIR, "Compressing bandwidth file.");
1463 } else {
1464 log_debug(LD_DIR, "Not compressing bandwidth file.");
1465 }
1466 connection_dir_buf_add((const char*)bandwidth, len, conn, 1);
1467 tor_free(bandwidth);
1468 return 0;
1469 }
1470 }
1471 write_short_http_response(conn, 404, "Not found");
1472 return 0;
1473}
1474
1475/** Helper function for GET robots.txt or /tor/robots.txt */
1476static int
1478{
1479 (void)args;
1480 {
1481 const char robots[] = "User-agent: *\r\nDisallow: /\r\n";
1482 size_t len = strlen(robots);
1483 write_http_response_header(conn, len, NO_METHOD, ROBOTS_CACHE_LIFETIME);
1484 connection_buf_add(robots, len, TO_CONN(conn));
1485 }
1486 return 0;
1487}
1488
1489/* Given the <b>url</b> from a POST request, try to extract the version number
1490 * using the provided <b>prefix</b>. The version should be after the prefix and
1491 * ending with the separator "/". For instance:
1492 * /tor/hs/3/publish
1493 *
1494 * On success, <b>end_pos</b> points to the position right after the version
1495 * was found. On error, it is set to NULL.
1496 *
1497 * Return version on success else negative value. */
1498STATIC int
1499parse_hs_version_from_post(const char *url, const char *prefix,
1500 const char **end_pos)
1501{
1502 int ok;
1503 unsigned long version;
1504 const char *start;
1505 char *end = NULL;
1506
1507 tor_assert(url);
1508 tor_assert(prefix);
1509 tor_assert(end_pos);
1510
1511 /* Check if the prefix does start the url. */
1512 if (strcmpstart(url, prefix)) {
1513 goto err;
1514 }
1515 /* Move pointer to the end of the prefix string. */
1516 start = url + strlen(prefix);
1517 /* Try this to be the HS version and if we are still at the separator, next
1518 * will be move to the right value. */
1519 version = tor_parse_long(start, 10, 0, INT_MAX, &ok, &end);
1520 if (!ok) {
1521 goto err;
1522 }
1523
1524 *end_pos = end;
1525 return (int) version;
1526 err:
1527 *end_pos = NULL;
1528 return -1;
1529}
1530
1531/* Handle the POST request for a hidden service descripror. The request is in
1532 * <b>url</b>, the body of the request is in <b>body</b>. Return 200 on success
1533 * else return 400 indicating a bad request. */
1534STATIC int
1535handle_post_hs_descriptor(const char *url, const char *body)
1536{
1537 int version;
1538 const char *end_pos;
1539
1540 tor_assert(url);
1542
1543 version = parse_hs_version_from_post(url, "/tor/hs/", &end_pos);
1544 if (version < 0) {
1545 goto err;
1546 }
1547
1548 /* We have a valid version number, now make sure it's a publish request. Use
1549 * the end position just after the version and check for the command. */
1550 if (strcmpstart(end_pos, "/publish")) {
1551 goto err;
1552 }
1553
1554 switch (version) {
1555 case HS_VERSION_THREE:
1556 if (hs_cache_store_as_dir(body) < 0) {
1557 goto err;
1558 }
1559 log_info(LD_REND, "Publish request for HS descriptor handled "
1560 "successfully.");
1561 break;
1562 default:
1563 /* Unsupported version, return a bad request. */
1564 goto err;
1565 }
1566
1567 return 200;
1568 err:
1569 /* Bad request. */
1570 return 400;
1571}
1572
1573/** Helper function: called when a dirserver gets a complete HTTP POST
1574 * request. Look for an uploaded server descriptor or rendezvous
1575 * service descriptor. On finding one, process it and write a
1576 * response into conn->outbuf. If the request is unrecognized, send a
1577 * 400. Always return 0. */
1578MOCK_IMPL(STATIC int,
1579directory_handle_command_post,(dir_connection_t *conn, const char *headers,
1580 const char *body, size_t body_len))
1581{
1582 char *url = NULL;
1583 const or_options_t *options = get_options();
1584
1585 (void) body_len;
1586
1587 log_debug(LD_DIRSERV,"Received POST command.");
1588
1590
1591 if (!public_server_mode(options)) {
1592 log_info(LD_DIR, "Rejected dir post request from %s "
1593 "since we're not a public relay.",
1595 write_short_http_response(conn, 503, "Not acting as a public relay");
1596 goto done;
1597 }
1598
1599 if (parse_http_url(headers, &url) < 0) {
1600 write_short_http_response(conn, 400, "Bad request");
1601 return 0;
1602 }
1603 log_debug(LD_DIRSERV,"rewritten url as '%s'.", escaped(url));
1604
1605 /* Handle HS descriptor publish request. We force an anonymous connection
1606 * (which also tests for encrypted). We do not allow single-hop client to
1607 * post a descriptor onto an HSDir. */
1608 if (!strcmpstart(url, "/tor/hs/")) {
1609 if (!connection_dir_is_anonymous(conn)) {
1610 write_short_http_response(conn, 503,
1611 "Rejecting single hop HS descriptor post");
1612 goto done;
1613 }
1614 const char *msg = "HS descriptor stored successfully.";
1615
1616 /* We most probably have a publish request for an HS descriptor. */
1617 int code = handle_post_hs_descriptor(url, body);
1618 if (code != 200) {
1619 msg = "Invalid HS descriptor. Rejected.";
1620 }
1621 write_short_http_response(conn, code, msg);
1622 goto done;
1623 }
1624
1625 if (!authdir_mode(options)) {
1626 /* we just provide cached directories; we don't want to
1627 * receive anything. */
1628 write_short_http_response(conn, 400, "Nonauthoritative directory does not "
1629 "accept posted server descriptors");
1630 goto done;
1631 }
1632
1633 if (authdir_mode(options) &&
1634 !strcmp(url,"/tor/")) { /* server descriptor post */
1635 const char *msg = "[None]";
1636 uint8_t purpose = authdir_mode_bridge(options) ?
1638
1639 {
1640 char *genreason = http_get_header(headers, "X-Desc-Gen-Reason: ");
1641 log_info(LD_DIRSERV,
1642 "New descriptor post, because: %s",
1643 genreason ? genreason : "not specified");
1644 tor_free(genreason);
1645 }
1646
1648 purpose, conn->base_.address, &msg);
1649 tor_assert(msg);
1650
1651 if (r == ROUTER_ADDED_SUCCESSFULLY) {
1652 write_short_http_response(conn, 200, msg);
1653 } else if (WRA_WAS_OUTDATED(r)) {
1654 write_http_response_header_impl(conn, -1, NULL, NULL,
1655 "X-Descriptor-Not-New: Yes\r\n", -1);
1656 } else {
1657 log_info(LD_DIRSERV,
1658 "Rejected router descriptor or extra-info from %s "
1659 "(\"%s\").",
1661 msg);
1662 write_short_http_response(conn, 400, msg);
1663 }
1664 goto done;
1665 }
1666
1667 if (authdir_mode_v3(options) &&
1668 !strcmp(url,"/tor/post/vote")) { /* v3 networkstatus vote */
1669 const char *msg = "OK";
1670 int status;
1671 if (dirvote_add_vote(body, approx_time(), TO_CONN(conn)->address,
1672 &msg, &status)) {
1673 write_short_http_response(conn, status, "Vote stored");
1674 } else {
1675 tor_assert(msg);
1676 log_warn(LD_DIRSERV, "Rejected vote from %s (\"%s\").",
1678 msg);
1679 write_short_http_response(conn, status, msg);
1680 }
1681 goto done;
1682 }
1683
1684 if (authdir_mode_v3(options) &&
1685 !strcmp(url,"/tor/post/consensus-signature")) { /* sigs on consensus. */
1686 const char *msg = NULL;
1687 if (dirvote_add_signatures(body, conn->base_.address, &msg)>=0) {
1688 write_short_http_response(conn, 200, msg?msg:"Signatures stored");
1689 } else {
1690 log_warn(LD_DIR, "Unable to store signatures posted by %s: %s",
1692 msg?msg:"???");
1693 write_short_http_response(conn, 400,
1694 msg?msg:"Unable to store signatures");
1695 }
1696 goto done;
1697 }
1698
1699 /* we didn't recognize the url */
1700 write_short_http_response(conn, 404, "Not found");
1701
1702 done:
1703 tor_free(url);
1704 return 0;
1705}
1706
1707/** If <b>headers</b> indicates that a proxy was involved, then rewrite
1708 * <b>conn</b>->address to describe our best guess of the address that
1709 * originated this HTTP request. */
1710static void
1711http_set_address_origin(const char *headers, connection_t *conn)
1712{
1713 char *fwd;
1714
1715 fwd = http_get_header(headers, "Forwarded-For: ");
1716 if (!fwd)
1717 fwd = http_get_header(headers, "X-Forwarded-For: ");
1718 if (fwd) {
1719 tor_addr_t toraddr;
1720 if (tor_addr_parse(&toraddr,fwd) == -1 ||
1721 tor_addr_is_internal(&toraddr,0)) {
1722 log_debug(LD_DIR, "Ignoring local/internal IP %s", escaped(fwd));
1723 tor_free(fwd);
1724 return;
1725 }
1726
1727 tor_free(conn->address);
1728 conn->address = tor_strdup(fwd);
1729 tor_free(fwd);
1730 }
1731}
1732
1733/** Called when a dirserver receives data on a directory connection;
1734 * looks for an HTTP request. If the request is complete, remove it
1735 * from the inbuf, try to process it; otherwise, leave it on the
1736 * buffer. Return a 0 on success, or -1 on error.
1737 */
1738int
1740{
1741 char *headers=NULL, *body=NULL;
1742 size_t body_len=0;
1743 int r;
1744
1745 tor_assert(conn);
1746 tor_assert(conn->base_.type == CONN_TYPE_DIR);
1747
1749 &headers, MAX_HEADERS_SIZE,
1750 &body, &body_len, MAX_DIR_UL_SIZE, 0)) {
1751 case -1: /* overflow */
1752 log_warn(LD_DIRSERV,
1753 "Request too large from %s to DirPort. Closing.",
1755 return -1;
1756 case 0:
1757 log_debug(LD_DIRSERV,"command not all here yet.");
1758 return 0;
1759 /* case 1, fall through */
1760 }
1761
1762 http_set_address_origin(headers, TO_CONN(conn));
1763 // we should escape headers here as well,
1764 // but we can't call escaped() twice, as it uses the same buffer
1765 //log_debug(LD_DIRSERV,"headers %s, body %s.", headers, escaped(body));
1766
1767 if (!strncasecmp(headers,"GET",3))
1768 r = directory_handle_command_get(conn, headers, body, body_len);
1769 else if (!strncasecmp(headers,"POST",4))
1770 r = directory_handle_command_post(conn, headers, body, body_len);
1771 else {
1772 log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
1773 "Got headers %s with unknown command. Closing.",
1774 escaped(headers));
1775 r = -1;
1776 }
1777
1778 tor_free(headers); tor_free(body);
1779 return r;
1780}
int tor_addr_parse(tor_addr_t *addr, const char *src)
Definition: address.c:1349
time_t approx_time(void)
Definition: approx_time.c:32
void authority_cert_get_all(smartlist_t *certs_out)
Definition: authcert.c:664
authority_cert_t * authority_cert_get_newest_by_id(const char *id_digest)
Definition: authcert.c:601
authority_cert_t * authority_cert_get_by_sk_digest(const char *sk_digest)
Definition: authcert.c:621
authority_cert_t * authority_cert_get_by_digests(const char *id_digest, const char *sk_digest)
Definition: authcert.c:648
Header file for authcert.c.
int authdir_mode(const or_options_t *options)
Definition: authmode.c:25
int authdir_mode_bridge(const or_options_t *options)
Definition: authmode.c:76
Header file for directory authority mode.
Authority certificate structure.
int base16_decode(char *dest, size_t destlen, const char *src, size_t srclen)
Definition: binascii.c:506
void buf_add_printf(buf_t *buf, const char *format,...)
Definition: buffers.c:568
buf_t * buf_new_with_capacity(size_t size)
Definition: buffers.c:356
void buf_add_string(buf_t *buf, const char *string)
Definition: buffers.c:561
Cached large directory object structure.
#define ARRAY_LENGTH(x)
compress_method_t compression_method_get_by_name(const char *name)
Definition: compress.c:411
unsigned tor_compress_get_supported_method_bitmask(void)
Definition: compress.c:336
tor_compress_state_t * tor_compress_new(int compress, compress_method_t method, compression_level_t compression_level)
Definition: compress.c:489
const char * compression_method_get_name(compress_method_t method)
Definition: compress.c:372
Headers for compress.c.
compress_method_t
Definition: compress.h:21
compression_level_t
Definition: compress.h:35
const or_options_t * get_options(void)
Definition: config.c:944
tor_cmdline_mode_t command
Definition: config.c:2468
Header file for config.c.
int connection_fetch_from_buf_http(connection_t *conn, char **headers_out, size_t max_headerlen, char **body_out, size_t *body_used, size_t max_bodylen, int force_complete)
Definition: connection.c:4340
bool connection_dir_is_global_write_low(const connection_t *conn, size_t attempt)
Definition: connection.c:3595
void connection_buf_add_buf(connection_t *conn, buf_t *buf)
Definition: connection.c:4833
const char * connection_describe_peer(const connection_t *conn)
Definition: connection.c:530
void connection_dir_buf_add(const char *string, size_t len, dir_connection_t *dir_conn, int done)
Definition: connection.c:4809
Header file for connection.c.
#define CONN_TYPE_DIR
Definition: connection.h:55
Header for conscache.c.
int consensus_cache_entry_get_valid_until(const consensus_cache_entry_t *ent, time_t *out)
Definition: consdiffmgr.c:1960
int consensus_cache_entry_get_fresh_until(const consensus_cache_entry_t *ent, time_t *out)
Definition: consdiffmgr.c:1944
consdiff_status_t consdiffmgr_find_diff_from(consensus_cache_entry_t **entry_out, consensus_flavor_t flavor, int digest_type, const uint8_t *digest, size_t digestlen, compress_method_t method)
Definition: consdiffmgr.c:660
int consensus_cache_entry_get_voter_id_digests(const consensus_cache_entry_t *ent, smartlist_t *out)
Definition: consdiffmgr.c:1928
consdiff_status_t consdiffmgr_find_consensus(struct consensus_cache_entry_t **entry_out, consensus_flavor_t flavor, compress_method_t method)
Definition: consdiffmgr.c:629
int consensus_cache_entry_get_valid_after(const consensus_cache_entry_t *ent, time_t *out)
Definition: consdiffmgr.c:1977
Header for consdiffmgr.c.
int crypto_digest256(char *digest, const char *m, size_t len, digest_algorithm_t algorithm)
int ed25519_public_from_base64(ed25519_public_key_t *pkey, const char *input)
Header for crypto_format.c.
int tor_memeq(const void *a, const void *b, size_t sz)
Definition: di_ops.c:107
#define tor_memneq(a, b, sz)
Definition: di_ops.h:21
#define DIGEST256_LEN
Definition: digest_sizes.h:23
Client/server directory connection structure.
static int handle_get_descriptor(dir_connection_t *conn, const get_handler_args_t *args)
Definition: dircache.c:1162
STATIC int directory_handle_command_post(dir_connection_t *conn, const char *headers, const char *body, size_t body_len)
Definition: dircache.c:1580
static compress_method_t srv_meth_pref_precompressed[]
Definition: dircache.c:203
static int handle_get_networkstatus_bridges(dir_connection_t *conn, const get_handler_args_t *args)
Definition: dircache.c:1404
int directory_handle_command(dir_connection_t *conn)
Definition: dircache.c:1739
static struct consensus_cache_entry_t * find_best_diff(const smartlist_t *digests, int flav, unsigned compression_methods, compress_method_t *compression_used_out)
Definition: dircache.c:613
static int digest_list_contains_best_consensus(consensus_flavor_t flavor, const smartlist_t *digests)
Definition: dircache.c:713
static void write_http_response_header(dir_connection_t *conn, ssize_t length, compress_method_t method, long cache_lifetime)
Definition: dircache.c:194
STATIC int parse_http_url(const char *headers, char **url)
Definition: dircache.c:72
static compress_method_t srv_meth_pref_streaming_compression[]
Definition: dircache.c:213
static int parse_one_diff_hash(uint8_t *digest, const char *hex, const char *location, const char *action)
Definition: dircache.c:556
static int handle_get_keys(dir_connection_t *conn, const get_handler_args_t *args)
Definition: dircache.c:1257
STATIC int handle_get_hs_descriptor_v3(dir_connection_t *conn, const get_handler_args_t *args)
Definition: dircache.c:1354
static int handle_get_current_consensus(dir_connection_t *conn, const get_handler_args_t *args)
Definition: dircache.c:850
static int handle_get_next_bandwidth(dir_connection_t *conn, const get_handler_args_t *args)
Definition: dircache.c:1444
static const url_table_ent_t url_table[]
Definition: dircache.c:368
#define FALLBACK_COMPRESS_METHOD
Definition: dircache.c:603
static int parse_or_diff_from_header(smartlist_t **digests_out, const char *headers)
Definition: dircache.c:575
static int handle_get_microdesc(dir_connection_t *conn, const get_handler_args_t *args)
Definition: dircache.c:1108
static int handle_get_robots(dir_connection_t *conn, const get_handler_args_t *args)
Definition: dircache.c:1477
static int handle_get_frontpage(dir_connection_t *conn, const get_handler_args_t *args)
Definition: dircache.c:481
static void parsed_consensus_request_clear(parsed_consensus_request_t *req)
Definition: dircache.c:756
static int client_likes_consensus(const struct consensus_cache_entry_t *ent, const char *want_url)
Definition: dircache.c:260
STATIC unsigned parse_accept_encoding_header(const char *h)
Definition: dircache.c:224
static void http_set_address_origin(const char *headers, connection_t *conn)
Definition: dircache.c:1711
#define MAX_DIR_UL_SIZE
Definition: dircache.c:48
static int parse_consensus_request(parsed_consensus_request_t *out, const get_handler_args_t *args)
Definition: dircache.c:775
static struct consensus_cache_entry_t * find_best_consensus(int flav, unsigned compression_methods, compress_method_t *compression_used_out)
Definition: dircache.c:652
static void write_http_response_headers(dir_connection_t *conn, ssize_t length, compress_method_t method, const char *extra_headers, long cache_lifetime)
Definition: dircache.c:181
static void warn_consensus_is_not_reasonably_live(const struct consensus_cache_entry_t *consensus, const char *flavor, time_t now, bool is_too_new)
Definition: dircache.c:509
STATIC int directory_handle_command_get(dir_connection_t *conn, const char *headers, const char *req_body, size_t req_body_len)
Definition: dircache.c:392
static void write_short_http_response(dir_connection_t *conn, int status, const char *reason_phrase)
Definition: dircache.c:94
static int handle_get_status_vote(dir_connection_t *conn, const get_handler_args_t *args)
Definition: dircache.c:1021
#define FULL_DIR_CACHE_LIFETIME
Definition: dircache.c:52
STATIC compression_level_t choose_compression_level(void)
Definition: dircache.c:300
static void write_http_response_header_impl(dir_connection_t *conn, ssize_t length, const char *type, const char *encoding, const char *extra_headers, long cache_lifetime)
Definition: dircache.c:129
static compress_method_t find_best_compression_method(unsigned compression_methods, int stream)
Definition: dircache.c:687
Header file for dircache.c.
int dir_split_resource_into_fingerprint_pairs(const char *res, smartlist_t *pairs_out)
Definition: directory.c:593
int connection_dir_is_encrypted(const dir_connection_t *conn)
Definition: directory.c:181
int dir_split_resource_into_fingerprints(const char *resource, smartlist_t *fp_out, int *compressed_out, int flags)
Definition: directory.c:652
bool connection_dir_is_anonymous(const dir_connection_t *dir_conn)
Definition: directory.c:201
char * http_get_header(const char *headers, const char *which)
Definition: directory.c:326
int parse_http_command(const char *headers, char **command_out, char **url_out)
Definition: directory.c:272
Header file for directory.c.
#define DIR_CONN_STATE_SERVER_WRITING
Definition: directory.h:30
void dirserv_spool_remove_missing_and_guess_size(dir_connection_t *conn, time_t cutoff, int compression, size_t *size_out, int *n_expired_out)
Definition: dirserv.c:644
int dirserv_get_routerdesc_spool(smartlist_t *spool_out, const char *key, dir_spool_source_t source, int conn_is_encrypted, const char **msg_out)
Definition: dirserv.c:245
spooled_resource_t * spooled_resource_new_from_cache_entry(consensus_cache_entry_t *entry)
Definition: dirserv.c:345
int dir_split_resource_into_spoolable(const char *resource, dir_spool_source_t source, smartlist_t *spool_out, int *compressed_out, int flags)
Definition: dirserv.c:212
Header file for dirserv.c.
dir_spool_source_t
Definition: dirserv.h:20
pending_vote_t * dirvote_add_vote(const char *vote_body, time_t time_posted, const char *where_from, const char **msg_out, int *status_out)
Definition: dirvote.c:3183
int dirvote_add_signatures(const char *detached_signatures_body, const char *source, const char **msg)
Definition: dirvote.c:3721
Header file for dirvote.c.
const char * escaped(const char *s)
Definition: escape.c:126
#define RFTS_IGNORE_MISSING
Definition: files.h:101
Header file for fp_pair.c.
Header file for geoip_stats.c.
void geoip_note_ns_response(geoip_ns_response_t response)
Definition: geoip_stats.c:395
@ GEOIP_CLIENT_NETWORKSTATUS
Definition: geoip_stats.h:26
void geoip_start_dirreq(uint64_t dirreq_id, size_t response_size, dirreq_type_t type)
Definition: geoip_stats.c:531
void geoip_note_client_seen(geoip_client_action_t action, const tor_addr_t *addr, const char *transport_name, time_t now)
Definition: geoip_stats.c:229
@ GEOIP_REJECT_BUSY
Definition: geoip_stats.h:43
@ GEOIP_SUCCESS
Definition: geoip_stats.h:32
@ GEOIP_REJECT_NOT_FOUND
Definition: geoip_stats.h:39
@ GEOIP_REJECT_NOT_MODIFIED
Definition: geoip_stats.h:41
@ GEOIP_REJECT_NOT_ENOUGH_SIGS
Definition: geoip_stats.h:35
int hs_cache_lookup_as_dir(uint32_t version, const char *query, const char **desc_out)
Definition: hs_cache.c:383
int hs_cache_store_as_dir(const char *desc)
Definition: hs_cache.c:346
Header file for hs_cache.c.
#define HS_VERSION_THREE
Definition: hs_common.h:23
hs_ident_dir_conn_t * hs_ident_server_dir_conn_new(const ed25519_public_key_t *blinded_pk)
Definition: hs_ident.c:68
Header file containing circuit and connection identifier data for the whole HS subsystem.
#define log_fn(severity, domain, args,...)
Definition: log.h:283
#define LD_REND
Definition: log.h:84
#define LD_PROTOCOL
Definition: log.h:72
#define LD_DIRSERV
Definition: log.h:90
#define LD_DIR
Definition: log.h:88
#define tor_free(p)
Definition: malloc.h:56
networkstatus_t * networkstatus_get_latest_consensus_by_flavor(consensus_flavor_t f)
int networkstatus_valid_after_is_reasonably_live(time_t valid_after, time_t now)
int networkstatus_parse_flavor_name(const char *flavname)
int networkstatus_valid_until_is_reasonably_live(time_t valid_until, time_t now)
char * networkstatus_getinfo_by_purpose(const char *purpose_string, time_t now)
Header file for networkstatus.c.
Networkstatus consensus/vote structure.
Master header file for Tor-specific functionality.
#define TO_CONN(c)
Definition: or.h:612
#define MAX_HEADERS_SIZE
Definition: or.h:122
consensus_flavor_t
Definition: or.h:763
#define ROUTER_MAX_AGE_TO_PUBLISH
Definition: or.h:161
long tor_parse_long(const char *s, int base, long min, long max, int *ok, char **next)
Definition: parse_int.c:59
int tor_asprintf(char **strp, const char *fmt,...)
Definition: printf.c:75
was_router_added_t dirserv_add_multiple_descriptors(const char *desc, size_t desclen, uint8_t purpose, const char *source, const char **msg)
Header file for process_descs.c.
char * rate_limit_log(ratelim_t *lim, time_t now)
Definition: ratelim.c:42
Header file for relay.c.
const char * relay_get_dirportfrontpage(void)
Definition: relay_config.c:77
Header for feature/relay/relay_config.c.
void rep_hist_note_desc_served(const char *desc)
Definition: rephist.c:2215
Header file for rephist.c.
bool is_local_to_resolve_addr(const tor_addr_t *addr)
: Return true iff the given addr is judged to be local to our resolved address.
Definition: resolve_addr.c:819
Header file for resolve_addr.c.
authority_cert_t * get_my_v3_authority_cert(void)
Definition: router.c:473
Router descriptor structure.
#define ROUTER_PURPOSE_GENERAL
#define ROUTER_PURPOSE_BRIDGE
const routerinfo_t * router_get_by_id_digest(const char *digest)
Definition: routerlist.c:779
Header file for routerlist.c.
static int WRA_WAS_OUTDATED(was_router_added_t s)
Definition: routerlist.h:116
was_router_added_t
Definition: routerlist.h:17
int public_server_mode(const or_options_t *options)
Definition: routermode.c:43
int server_mode(const or_options_t *options)
Definition: routermode.c:34
Header file for routermode.c.
smartlist_t * smartlist_new(void)
void smartlist_add(smartlist_t *sl, void *element)
#define SMARTLIST_FOREACH_BEGIN(sl, type, var)
#define SMARTLIST_FOREACH(sl, type, var, cmd)
#define SMARTLIST_DEL_CURRENT(sl, var)
int smartlist_split_string(smartlist_t *sl, const char *str, const char *sep, int flags, int max)
signed_descriptor_t cache_info
uint8_t state
Definition: connection_st.h:49
unsigned int type
Definition: connection_st.h:50
tor_addr_t addr
Definition: conscache.c:32
const uint8_t * body
Definition: conscache.c:56
smartlist_t * spool
struct tor_compress_state_t * compress_state
time_t if_modified_since
Definition: dircache.c:325
const char * headers
Definition: dircache.c:329
const char * url
Definition: dircache.c:327
unsigned compression_supported
Definition: dircache.c:322
uint8_t digest_sha3_as_signed[DIGEST256_LEN]
char * BridgePassword_AuthDigest_
char * V3BandwidthsFile
int BridgeAuthoritativeDir
smartlist_t * diff_from_digests
Definition: dircache.c:747
consensus_flavor_t flav
Definition: dircache.c:740
uint8_t purpose
char identity_digest[DIGEST_LEN]
#define STATIC
Definition: testsupport.h:32
#define MOCK_IMPL(rv, funcname, arglist)
Definition: testsupport.h:133
void format_rfc1123_time(char *buf, time_t t)
Definition: time_fmt.c:213
int parse_http_time(const char *date, struct tm *tm)
Definition: time_fmt.c:440
void format_local_iso_time(char *buf, time_t t)
Definition: time_fmt.c:316
int tor_timegm(const struct tm *tm, time_t *time_out)
Definition: time_fmt.c:171
#define tor_assert(expr)
Definition: util_bug.h:103
#define IF_BUG_ONCE(cond)
Definition: util_bug.h:254
int strcasecmpstart(const char *s1, const char *s2)
Definition: util_string.c:227
int strcmpstart(const char *s1, const char *s2)
Definition: util_string.c:217