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