dircache.c 59 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742
  1. /* Copyright (c) 2001-2004, Roger Dingledine.
  2. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
  3. * Copyright (c) 2007-2019, 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/authmode.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/routermode.h"
  24. #include "feature/rend/rendcache.h"
  25. #include "feature/stats/geoip_stats.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. log_info(LD_DIRSERV,"DIRCACHE headers %s", escaped(headers));
  1550. log_info(LD_DIRSERV,"DIRCACHE body %s", escaped(body));
  1551. if (!strncasecmp(headers,"GET",3))
  1552. r = directory_handle_command_get(conn, headers, body, body_len);
  1553. else if (!strncasecmp(headers,"POST",4))
  1554. r = directory_handle_command_post(conn, headers, body, body_len);
  1555. else {
  1556. log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
  1557. "Got headers %s with unknown command. Closing.",
  1558. escaped(headers));
  1559. r = -1;
  1560. }
  1561. tor_free(headers); tor_free(body);
  1562. return r;
  1563. }