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