dircache.c 59 KB

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